007 Programacion en c++

59
3.2.3e Secuencias de escape §1 Sinopsis Como se indicó al tratar del código ASCII ( 2.2.1a ), existen 33 de estos caracteres que no tienen representación gráfica; son los denominadoscaracteres de control. Con el fin de poder representarlos en el código 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 representación de los caracteres de control, por extensión pueden representarse de este modo todos los códigos ASCII. Además se dispone de algunos símbolos predefinidos para los caracteres más frecuentes. Por ejemplo, \n se utiliza para representar el carácter nueva línea (decimal 10). Los símbolos utilizados se muestran en la tabla adjunta. Secuencia Valor Símbolo Descripción \a 0x07 BEL Sonido audible (bell) \b 0x08 BS Retroceso (backspace) \f 0x0C FF Salto de formato (formfeed) \n 0x0A LF Saltar una línea (linefeed) \r 0x0D CR Retorno de carro (carriage return) \t 0x09 HT Tabulación horizontal (H Tab) \v 0x0B VT Tabulación vertical (V Tab) \\ 0x5c \ Barra invertida (backslash) [2] \' 0x27 ' Apóstrofo (comilla simple) \" 0x22 " Doble comilla \? 0x3F ? Interrogación \O cualquiera cualquiera O = cadena de hasta tres dígitos octales \xH cualquiera cualquiera H = cadena de dígitos hexadecimales

Transcript of 007 Programacion en c++

323e Secuencias de escape

sect1 Sinopsis

Como se indicoacute al tratar del coacutedigo ASCII ( 221a) existen 33 de estos caracteres que no tienen representacioacuten graacutefica son los denominadoscaracteres de control Con el fin de poder representarlos en el coacutedigo fuente se recurrioacute al artificio de representarlos utilizando una barra invertida () seguida de otra serie de caracteres

sect2 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 representacioacuten de los caracteres de control por extensioacuten pueden representarse de este modo todos los coacutedigos ASCII Ademaacutes se dispone de algunos siacutembolos predefinidos para los caracteres maacutes frecuentes Por ejemplo n se utiliza para representar el caraacutecter nueva liacutenea (decimal 10) Los siacutembolos utilizados se muestran en la tabla adjunta

Secuencia Valor Siacutembolo Descripcioacuten

a 0x07 BEL Sonido audible (bell)

b 0x08 BS Retroceso (backspace)

f 0x0C FF Salto de formato (formfeed)

n 0x0A LF Saltar una liacutenea (linefeed)

r 0x0D CR Retorno de carro (carriage return)

t 0x09 HT Tabulacioacuten horizontal (H Tab)

v 0x0B VT Tabulacioacuten vertical (V Tab)

0x5c Barra invertida (backslash) [2]

0x27 Apoacutestrofo (comilla simple)

0x22 Doble comilla

0x3F Interrogacioacuten

O cualquiera cualquiera O = cadena de hasta tres diacutegitos octales

xH cualquiera cualquiera H = cadena de diacutegitos hexadecimales

XH cualquiera cualquiera H = cadena de diacutegitos hexadecimales

Ejemplo

char campana = a caraacutecter ASCII 7cout ltlt campana ltlt endl genera un sonido audible

sect3 La barra invertida ( ) se utiliza junto con nuacutemeros octales o hexadecimales [3] para

representar siacutembolos ASCII ( 221a) incluyendo los denominados caracteres de control (tambieacuten llamados caracteres no imprimibles) que no tienen representacioacuten directa en ninguacuten caraacutecter

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

sect31 Octal

Rango 0 a 377

Ejemplos0 Caraacutecter nulo (fin de cadena)

03 Ctr-C

07 Bell

013 Vertical TAB

077

sect32 Hexadecimal

Rango x00 a xFF

Ejemplos0 Caraacutecter nulo (fin de cadena)x3 Ctr-Cx7 BellxB Vertical TABx3F

sect4 Los nuacutemeros mayores que los indicados generan un error de compilacioacuten Numeric constant too large Por ejemplo el octal 777 es mayor que el maacuteximo permitido (377) por lo que produciriacutea un error El primer caraacutecter no octal o no hexadecimal que se encuentre en una secuencia octal o hexadecimal respectivamente sentildeala el final de la secuencia de escape Por ejemplo

printf(x0721Un Sistema Operativo)

La sentencia anterior deberiacutea ser interpretada como el hexadecimal x07 (BEL) y 21 Un Sistema Operativo aunque quizaacutes el compilador lo interprete como hexadecimal x072 (el caraacutecter r) y la cadena literal 1Un sistema Operativo Para evitar este tipo de ambiguumledades debe escribirse

printf(x07 21Un Sistema Operativo)

Tambieacuten pueden darse ambiguumledades si una secuencia de escape en octal es seguida por un nuacutemero no octal Por ejemplo dado que los diacutegitos 8 y 9 no son octales vaacutelidos la constante 258 puede ser interpretada como una constante de dos caracteres 25 (Ctrl-U) y un 8

sect5 Trigrafos

Con la extensioacuten de la informaacutetica a paiacuteses distintos del aacutembito anglosajoacuten 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 mayoriacutea de teclados en Espantildeol no existe la tilde ~ como un caraacutecter independiente lo que no es inconveniente para la escritura normal ya que la uacutenica ocurrencia en este signo en Espantildeol es en la letra entildee Ntilde que siacute dispone de su correspondiente tecla Pero la referida ausencia de la tilde como siacutembolo independiente resulta una molestia para los programadores ya que el fuente requiere en ocasiones incluir dicho siacutembolo Para resolver el problema se adoptoacute el convenio que estos caracteres conflictivos podiacutean representarse en el coacutedigo fuente mediante parejas y ternas de caracteres los denominados diacutegrafos y triacutegrafos que se muestran en la tabla adjunta

Triacutegrafo Caraacutecter Diacutegrafo = ( [ lt ) ] gt ^ lt lt gt gt | - ~

Nota la interpretacioacuten de estos triacutegrafos retarda considerablemente la accioacuten del compilador por lo que Borland C++ incluye un traductor especiacutefico el programa trigraphexe que puede traducir el coacutedigo fuente antes de la compilacioacuten [4]

Tema relacionado Representacioacuten expliacutecita de operadores loacutegicos ( 498)

323f Constantes de cadena

sect1 Sinopsis

Las constantes de cadena tambieacuten llamadas cadenas literales o alfanumeacutericas (String literals) son utilizadas para albergar secuencias de caracteres alfanumeacutericos y forman una categoriacutea especial dentro de las constantes aunque tambieacuten pueden ser consideradas un caso

especial de matrices de caracteres ( 434) Se representan en el fuente como una secuencia de caracteres entre comillas dobles ()

Esto es una cadena literalLEsto es una cadena de caracteres anchos

Vistas con cierta perspectiva las cadenas literales aparecen como un tipo algo extrantildeo que en cierta forma desentona del resto de entidades del universo C++ y que no deberiacutean tener cabida en eacutel En realidad hay algo de esto representan una herencia de su antecesor C en el que se utilizan estas extrantildeas construcciones para almacenar texto alfanumeacuterico en el que su punto final se identifica mediante el caraacutecter nulo [2]

El texto de una cadena literal puede contener cualquier caraacutecter del juego de caracteres

imprimibles ASCII ( 221a) Para representar los caracteres no imprimibles se utilizan las

denominadas secuencias de escape un truco que consiste en sustituir cada caraacutecter no imprimible por una secuencia de dos o tres caracteres Naturalmente una cadena literal no debe contener un caraacutecter nulo en su interior (que como hemos indicado sentildeala el final de la cadena) en caso contrario al aplicarse las funciones de Libreriacutea Estaacutendar claacutesicas (heredadas de C) el resultado es impredecible

sect11 El punto importante a entender aquiacute podriacutea sintetizarse en que desde la oacuteptica 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 atencioacuten a que el antiguo coacutedigo C sea compatible con los

compiladores C++

Si la cadena no estaacute precedida por la letra L es una matriz de caracteres tipo const char (

323) tambieacuten denominada cadena estrecha u ordinaria (Narrow string literal)

Si la cadena estaacute precedida por la letra L los miembros de la matriz son caracteres anchos

( 221a1) del tipo const w_char y se denomina cadena ancha (Wide string literal)

Estos objetos tienen almacenamiento estaacutetico en el sentido indicado en 226 es decir que el compilador conoce los valores en tiempo de compilacioacuten y que probablemente sean

guardados en el segmento ( 132) [4]

sect12 Generalmente aparecen a la derecha en expresiones de asignacioacuten o como paraacutemetros de funciones pueden aparecer incluso como valores devueltos por funciones Ejemplos

char ptr = Hola mundoprintf(sn Soy una cadena literal)cout ltlt acabo de llegar ltlt endlreturn Se termina la funcioacuten

sect2 Secuencias de escape

Dentro de las comillas se pueden representar caracteres especiales (no imprimibles)

mediante secuencias de escape ( 323e) Por ejemplo el coacutedigo

ttNombretDireccioacutennn

Se representa como

Nombre Direccioacuten

Nombre es precedido por dos tabulaciones Direccioacuten esta precedido por una tabulacioacuten La liacutenea va seguida de dos nueva liacutenea (NL) La secuencia proporciona las comillas interiores Si se

compila con la opcioacuten -A para compatibilidad ANSI la secuencia de escape es traducida por el compilador a

sect3 Como hemos sentildealado en C++ las cadenas alfanumeacutericas son teacutecnicamente matrices de caracteres constantes se almacenan internamente como secuencias de caracteres maacutes un caraacutecter final nulo 0 lo que significa que el almacenamiento usado es igual a la longitud visible de la cadena mas uno Seguacuten esto la cadena nula es almacenada como un solo caraacutecter 0 y no hay maacutes liacutemite que la memoria disponible para la longitud posible de una cadena Por ejemplo la cadena Holan se guarda internamente como

H o l a n 0

Nota histoacuterica El meacutetodo de identificar el final de cadena mediante un caraacutecter nulo es ineficiente y aparte de que no permite utilizar cadenas que contengan un caraacutecter nulo en su interior (por ejemplo ficheros binarios) su manejo conlleva problemas de rendimiento [3]

Aparentemente la razoacuten por la que C y C++ utilizan este meacutetodo se debe a que C se desarrolloacute

sobre maacutequinas Unix ( 1 ) y a su vez este sistema operativo fue desarrollado inicialmente sobre una maacutequina DEC (Digital Equipment Corporation) PDP-7 que teniacutean un tipo de dato denominado ASICZ (ASCII con un Zero al final) que era directamente reconocible por su ensamblador

sect4 Peculiaridades

En el preaacutembulo sentildealamos 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 ninguacuten 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 uacutenica singularidad es que el compilador C++ les permite ciertas formas particulares de definicioacuten y declaracioacuten que les confiere cierta personalidad

Por ejemplo el hecho de inicializarlas directamente con expresiones como las sentildealadas sect12 o que antildeada automaacuteticamente el caraacutecter nulo de terminacioacuten a los caracteres expliacutecitamente indicados por el programador

Respecto a esto uacuteltimo solo tiene justificacioacuten histoacuterica porque el caraacutecter nulo se utilizaba en las antiguas funciones de libreriacutea para indicar el final de la cadena Por esta razoacuten aunque es posible incluir caracteres nulos dentro de las cadenas literales Por ejemplo Hola0 mundo no estaacute garantizado que funcione en todos los casos (seraacute malinterpretado por las funciones printf strcpy y strlen de la Libreriacutea Estaacutendar)

Ejemplo

char ptr = Hola0 mundoprintf(sn ptr)

Salida

Hola

sect5 Una cadena nula (vaciacutea) se representa o 0 tiene un solo caraacutecter el caraacutecter nulo (ver a continuacioacuten) Observe que desde el punto de vista del Rvalue la constante de cadena A es A

0 mientras que la constante caraacutecter ( 323d) A es A

Se considera que la longitud de un NTBS es el nuacutemero de caracteres que preceden al de terminacioacuten de forma que la cadena nula tiene longitud 0 (aunque en realidad contiene un caraacutecter) Sin embargo el valor de la cadena incluye el caraacutecter de final

Conviene no confundir una constante de cadena (matriz) de un solo caraacutecter con un

caraacutecter char constante ( 323d) o variable ( 221a) La cadena de un solo caraacutecter es necesariamente la cadena nula su uacutenico elemento es el de fin de cadena Ejemplo

char x1= a L1 variable x1 tipo char valor == ASCII a == 97 decimalconst char x2= a L2 constante x2 tipo const charchar x3 = a L3 variable x3 tipo puntero-a-char sentildeala a cadena de dos caracteres 97 y 0 decimalconst char x4 = a L4 variable x4 tipo puntero a constante caraacutecterchar x5[1]= a L5 variable x5 tipo matriz de un caraacutecter valor x[0]== a == 97 decimal

Los objetos representados por los Rvalues ( 215) de las expresiones anteriores son de distinto tipo y se almacenan con tamantildeos distintos La primera segunda y quinta son constantes caraacutecter (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 tambieacuten muy importante sentildealar que la asignacioacuten

str = AEIOU

solo es posible si str se ha declarado previamente como puntero a caraacutecter es decir

char str sectg

Aunque se puede declarar y definir en la misma sentencia (preferible)

char str = AEIOU secth

El lector observador advertiraacute en la expresioacuten anterior una evidente inconsistencia en la gramaacutetica del C++ En efecto como se ha sentildealado las cadenas literales son de caracteres constantes En

consecuencia no asignables a punteros tales como los definidos en sectg o secth teacutecnicamente punteros a caraacutecter Teoacutericamente solo hubiese sido aceptable la asignacioacuten a puntero-a-caraacutecter-constante tal como

const char str = AEIOU secti

ya que un puntero-a-constante-tipoX no es intercambiable por un puntero-a-tipoX ( 421a) La razoacuten de esta inconsistencia en la definicioacuten de las cadenas literales hay que buscarla en otra de las desafortunadas herencias del C claacutesico y en la necesidad de mantener compatibilidad con millones de liacuteneas de coacutedigo existente En C y en las primitivas versiones de C++ las cadenas literales eran consideradas como de tipo char (puntero a caraacutecter)

Aunque la mayoriacutea de compiladores C++ permiten este tipo de sentencias por razones de tipo histoacuterico parece que tal permisividad tiende a ser deprecated (a extinguir) de forma que las uacuteltimas revisiones de algunos compiladores pueden lanzar una advertencia o error en tales circunstancias La forma canoacutenica de definir este tipo de cadenas seriacutea

const char str[] = AEIOU

La expresioacuten secth define una matriz de seis caracteres constantes (almacenado en alguacuten sitio) que no tiene identificador simple (nombre) Tambieacuten define un puntero str al primer elemento de la matriz (maacutes formalmente es un puntero a caraacutecter) Por tanto a falta de un nombre la matriz tiene que ser accedida a traveacutes del puntero (que tendraacute que ser tratado como tal -puntero-) Sin embargo las expresiones

char arr[] = AEIOU sectjchar arr[6] = AEIOUchar arr[6] = AEIOU0char arr[6] = AEIOUchar arr[6] = AEIOU0

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 (secth ) str es un puntero un objeto que puede ser usado con el aacutelgebra de punteros Por ejemplo es vaacutelida la expresioacuten str++ que

equivale a str = str+1 En los otros cinco casos (sectj ) arr es un nemoacutenico que representa una matriz y la expresioacuten arr++ que equivale a arr = arr+1 es ilegal El operando arr+1 es tratado como (amparr[0])+1 lo que es correcto (a un puntero se le puede sumar un entero) La asignacioacuten no seriacutea correcta porque intentariacutea asignar el puntero amparr[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 asignacioacuten 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 asignacioacuten del tipo x = aeiou Si tiene en cambio poderosas funciones en su Libreriacutea Estaacutendar para hacer todo tipo de manipulaciones con cadenas alfanumeacutericas

Es tambieacuten importante distinguir otra diferencia entre las expresiones

char a1[6] = AEIOU0 p1 = ampa1[0]char a2 = AEIOU

Ambas producen matrices de caracteres absolutamente ideacutenticos en contenido y tamantildeo pero a1 es una matriz por lo que sus elementos podriacutean ser alterados usando el identificador Por ejemplo es vaacutelido a1[1]= e o su equivalente (p1+1)=e En cambio un intento anaacutelogo sobre el segundo obliga a usar necesariamente la versioacuten con puntero (a2+1)=e Ademaacutes de que por las razones ya expuestas [2] el resultado no estaacute 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 todaviacutea la asignacioacuten

a2 = aeiou

En este caso el compilador almacena en alguacuten sitio la cadena aeiou0 y asigna a a2 la direccioacuten 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 ninguacuten modo aunque sigue malgastando espacio de memoria

Tambieacuten es posible declarar cadenas de caracteres anchos con el prefijo L como en el ejemplo

wchar_t wptr = Laeiou

en este caso wptr sentildeala una cadena de caracteres anchos ( 221a1) la cadena es del tipo const wchar_t

Para saber la longitud de una constante literal es necesario que el programa repase la cadena hasta encontrar el caraacutecter de fin de cadena lo que se consigue con la funcioacuten de libreriacutea strlen (incluida en la cabecera estaacutendar ltstringhgt) que proporciona la longitud sin contar el caraacutecter final

sect6 Concatenacioacuten de cadenas

Las cadenas literales adyacentes separadas solo por un especio son automaacuteticamente

concatenadas durante la fase de preprocesado ( 141) de la compilacioacuten Por ejemplo Hola mundo es equivalente a Hola mundo Tambieacuten puede usarse la barra invertida ( ) como siacutembolo de continuacioacuten para extender una cadena literal maacutes allaacute del liacutemite de una liacutenea

puts(En realidad esto es una cadena de una linea)char p = Esto es en otra cadena tambieacuten de una sola liacutenea

La concatenacioacuten suprime el caraacutecter nulo de final en las cadenas intermedias y mantiene el de la uacuteltima Esta operacioacuten no altera el significado de los caracteres que intervienen en las cadenas concatenadas Por ejemplo la concatenacioacuten

xA B

Produce la cadena

xAB

que tiene tres caracteres el hexadecimal xA el caraacutecter B y el caracter final nulo 0 En vez del caraacutecter hexadecimal xAB

La concatenacioacuten de cadenas anchas y estrechas tiene resultados impredecibles

323g Constantes de enumeracioacuten

sect1 Sinopsis

Existe un tipo especial de variables denominadas variables enumeradas o

simplemente enumeraciones ( 48 ) Se caracterizan por poder adoptar valores entre una seleccioacuten de constantes enteras denominadas enumeradores cuyos valores son establecidos en el momento de la declaracioacuten del nuevo tipo Como se ha sentildealado son enteros y (una vez establecidos) de valor constante razoacuten por la que se los denomina tambieacuten constantes de enumeracioacuten

Ejemplo

enum estado MALO =0 REGULAR =1 BUENO =2 EXTRA =3

La sentencia anterior declara estado como un tipo de variable de enumeracioacuten Los miembros de esta clase pueden adoptar los valores indicados y son representados por los nemoacutenicos MALO REGULAR BUENO y EXTRA Estas cuatro constantes son los enumeradores del nuevo tipo

Como advertencia a lo indicado hasta aquiacute no confundir la enumeracioacuten (la variable) con los enumeradores (las constantes enteras que delimitan el conjunto de valores posibles de la variable) Tambieacuten 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 = EXTRAestado tu_estado = REGULAR stdcout ltlt Mi estado actual es ltlt mi_estado ltlt endl -gt Mi estado actual es 3

En el caso anterior estado es una enumeracioacuten (tipo geneacuterico) 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 (geneacuterico) con un tipo enum concreto una instancia (variable enumerada) de ese tipo ni con los valores concretos (constantes de enumeracioacuten) que puede adoptar

Para facilitar la legibilidad los identificadores de las constantes de enumeracioacuten son nemoacutenicos y sus nombres suelen estar en mayuacutesculas debido a una larga tradicioacuten CC++ de representar de este modo las constantes

Ya hemos sentildealado que estas constantes (enumeradores) son de tipo entero por lo que pueden ser utilizadas en cualquier expresioacuten donde sean permitidas las constantes enteras Sus identificadores deben ser uacutenicos dentro del aacutembito de la declaracioacuten enum Se permiten inicializadores negativos los valores que adoptan los enumeradores suelen ser uacutenicos (aunque se permiten duplicidades) Para una visioacuten maacutes detallada de las declaraciones de estas constantes

ver enumeraciones ( 48 ) y la explicacioacuten que sigue sobre la palabra clave enum

sect2 Sintaxis

enum [ltnombre-de-tipogt] ltnombr-constgt [= ltvalorgt] [lista_var]

Puede omitirse la palabra clave enum siempre que el nemoacutenico ltnombre-de-tipogt no sea empleado para nada maacutes en el mismo aacutembito Ejemplo

calidad BUENA REGULAR MALA

En este caso el compilador presupone que calidad es un enumerador y no debe existir otra

definicioacuten en el mismo aacutembito de nombres En otras palabras calidad no debe utilizarse en el mismo aacutembito para designar otro objeto

ltnombre-de-tipogt es una etiqueta opcional que identifica al conjunto Puede omitirse si no se va a usar ninguna otra variable de este tipo de enumeracioacuten Ejemplo

enum CIERTO DUDOSO FALSO

ltnombr-constgt es el nombre de la constante de enumeracioacuten (enumerador) a la que opcionalmente puede asignarse el valor definido porltvalorgt En el ejemplo anterior son tres CIERTO DUDOSO y FALSO

ltvalorgt debe ser un entero (ya se ha sentildealado que los enumeradores son constantes

enteras) Si no se especifica ninguacuten valor se supone que es ltpreviogt + 1 donde ltpreviogt es el valor del enumerador anterior de la lista (el valor por defecto para el primero es cero) ltvalorgtpuede ser cualquier expresioacuten que resulte en un entero positivo o negativo (despueacutes de posible conversioacuten a entero)

ltlista_vargt 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 enumeracioacuten de nombre geneacuterico calidad las variables de este tipo pueden adoptar tres valores 0 1 y 2 identificados respectivamente por los nemoacutenicos BUENO REGULAR y MALO ademaacutes se definen dos variables del nuevo

tipo nota yestado

enum calidad BUENO REGULAR MALO nota estado

sect3 Descripcioacuten

La palabra clave enum define una enumeracioacuten 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 nemoacutenicos Por ejemplo la declaracioacuten

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 nemoacutenicos DOM LUNSAB Ademaacutes 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 nemoacutenicos ULT BW40 C40 BW80 C80 y MONO

Los valores asignados a los enumeradores dependen del formato de la declaracioacuten 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 Ademaacutes como puede comprobarse las expresiones de inicializacioacuten pueden incluir enumeradores previamente declarados

Los valores de los enumeradores no tienen porqueacute ser uacutenicos como en el ejemplo que sigue

enum estado BUENO MALO = 1 REGULAR = 1

326 Puntuadores

sect1 Sinopsis

Los signos de puntuacioacuten del lenguaje C++ juegan el mismo papel que sus homoacutenimos en el lenguaje natural escrito Conocidos tambieacuten comopuntuadores [1] son los que se citan a continuacioacuten La mayoriacutea de ellos tienen un doble uso y en ocasiones funcionan tambieacuten

comooperadores ( 49)

[ ] ( ) = ^ amp ndash + | ~ lt gt

sect2 Corchetes [ ]

Los corchetes indican subiacutendices de matrices uni y multi dimensionales

char ch str[] = Cadena de caracteresint mat[3][4] Matriz de 3 x 4ch = str[3] cuarto elemento

sect3 Pareacutentesis ( )

Los pareacutentesis sirven para agrupar expresiones alterar la precedencia normal de los operadores y su asociatividad aislar expresiones condicionales indicar llamadas a funciones y sentildealar los paraacutemetros de estas La sintaxis de C++ exige indefectiblemente el uso de pareacutentesis en muacuteltiples ocasiones En los ejemplos que siguen se muestran algunos usos

d = c (a + b) modifica la precedencia normalif (d == z) ++x imprescindible en la sentencia iffor (x =1 xlt10 x++) imprescindible en la sentencia forfunc() sentildeala llamada a funcioacutenint func() declara funcioacutenint (fptr)() declara puntero a funcioacutenfptr = func asigna valor al puntero

Observe que en el uacuteltimo caso la ausencia de pareacutentesis equivale a ampfunc ( 424a )

Se recomienda el uso de pareacutentesis en las macro-definiciones para evitar problemas potenciales en la expansioacuten Por ejemplo

define CUBO(x) ((x) (x) (x))

sect4 Llaves

Los pares de llaves sentildealan el comienzo y final de una sentencia compuesta es decir bloques de coacutedigo (grupos de sentencias que son tratadas como una unidad) Constituyen el segundo paso (despueacutes de las sentencias) en la estructuracioacuten y compartimentacioacuten del coacutedigo C++

if (d == z) ++x func()

Un bloque es una sentencia compuesta se trata de una sucesioacuten (que puede estar vaciacutea) de sentencias delimitadas por un par de corchetes Desde el punto de vista sintaacutectico un bloque puede ser considerado como una sola sentencia Juega un papel importante en el aacutembito (scope) de los identificadores puesto que un identificador declarado dentro de un bloque tiene un aacutembito

que comienza en el punto de la declaracioacuten 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)

Despueacutes del corchete de cierre no se necesita el punto y coma de fin de sentencia

if (statement) punto y coma ilegal else

Nota las llaves sirven tambieacuten en C++ para otros usos distintos de la pura delimitacioacuten de bloques de coacutedigo Por ejemplo en la definicioacuten de estructuras uniones y clases en cuyo caso si puede ser necesaria la inclusioacuten del punto y coma despueacutes de la llave de cierre

sect5 Coma

La coma como puntuador se utiliza para separar los elementos en las listas de paraacutemetros de una funcioacuten

void func(int n float f char ch)

La coma se usa tambieacuten como un operador en las expresiones con coma ( 4105) Es posible mezclar los dos usos (separador en lista de paraacutemetros y operador) pero deben usarse pareacutentesis para distinguirlos

sect6 Punto y coma

El punto y coma es el signo de fin de sentencia Cualquier expresioacuten legal C++ terminada por un punto y coma (incluyendo la expresioacuten vaciacutea - un punto y coma aislado-) es interpretado como una

sentencia conocidas como sentencia-expresioacuten ( 410) La expresioacuten se evaluacutea y el resultado se descarta si no tiene efectos colaterales C++ la ignora

a + b evaluacutea a + b descarta el resultado++a efecto lateral en a se descarta el valor ++a expresioacuten vaciacutea = sentencia nula

El punto y coma se usa a veces para crear sentencias nulas

for (i = 0 i lt n i++) sentencia nula (hacer nada)

sect7 Dos puntos

Los dos puntos se utilizan para sentildealar sentencias etiquetadas ( 4101)

comienzo x=0 comienzo es la etiquetagoto comienzo

sect8 Puntos suspensivos

Los puntos suspensivos tambieacuten 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 nuacutemero variable de argumentos o pueden ser de tipo variable ( 441) Por ejemplo

void func(int n char ch)

Este prototipo de funcioacuten declara que func estaacute definida de modo que debe ser llamada con al

menos dos argumentos un int y un char Ademaacutes puede tener un cierto nuacutemero de argumentos adicionales (puede omitirse la coma antes de la elipsis)

Se utiliza tambieacuten para indicar que un manejador de excepciones (handler) puede capturar una

excepcioacuten de cualquier tipo ( 162) Ejemplo

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

Nota como podeacuteis ver en ocasiones mi uso particular en los ejemplos de los tres puntos es para indicar cualquier nuacutemero de sentencias Espero que no sea motivo de confusioacuten Desde luego en el caso anterior seriacutea maacutes correcta la notacioacuten

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

sect9 Asterisco

El asterisco puede ser utilizado en C++ de tres formas como una declaracioacuten de tipo de variable

(variable de puntero 42 ) como operador de indireccioacuten (tambieacuten llamado operador

de dereferencia 4911a) y como operador de multiplicacioacuten

Ejemplos

char char_ptr declara puntero a caraacutecterx = int_ptr operador de indireccioacutenl = 2 314 r operador multiplicacioacuten

sect10 Signo igual =

El signo igual = separa la declaracioacuten de variables de las listas de inicializacioacuten

char array[5] = 1 2 3 4 5

Recordemos que al contrario que en C donde las declaraciones no pueden estar precedidas por ninguacuten coacutedigo deben ir al principio en C++ las declaraciones de cualquier tipo pueden aparecer en cualquier punto del coacutedigo (con algunas restricciones)

En la lista de argumentos de una funcioacuten el signo igual indica el valor por defecto para un paraacutemetro

int f(int i = 0) el valor por defecto de k es cero

El signo igual es tambieacuten utilizado como operador de asignacioacuten ( 492) Ejemplo

x = yz += 5

sect11 Almohadilla

Si la almohadilla aparecen en el primer caraacutecter (distinto de espacio en blanco) de una liacutenea

sentildeala directivas de preproceso ( 4910) En este caso es un operador especiacutefico de la fase

de preproceso del coacutedigo fuente Significa una opcioacuten del preprocesador ( 14) que no tiene porqueacute estar asociada necesariamente a generacioacuten de coacutedigo Las directivas se situacutean generalmente al comienzo del programa aunque legalmente pueden aparecer en cualquier punto

Ejemplos de directivas de preproceso

(null directive)define NULO 0include ltstdiohgt

4 Estructura del lenguaje

sect1 Sinopsis

Esta parte proporciona una definicioacuten formal del lenguaje C++ describiendo las formas en que

pueden agruparse correctamente los tokens ( 32) palabras que constituyen el lenguaje entendible por el compilador para formar declaraciones expresiones y otras unidades significativas Para su anaacutelisis lo hemos descompuesto en 13 grupos seguacuten la clasificacioacuten que sigue

sect41 Declaraciones

ObjetosReferencias amp definicionesDefinicioacuten provisionalAacutembitoVisibilidadDuracioacutenUnidad de compilacioacutenEnlazado

Sintaxis de declaraciones

Conversiones aritmeacuteticasInicializacioacutenEspecificadores de clase de almacenamientoModificadores auxiliaresModificadores de funcioacuten

sect42 Punteros

Puntero a objetoDeclaracioacuten de punterosAritmeacutetica de punterosReferenciasPuntero a funcioacuten

sect43 Matrices

Declaracioacuten de matricesMatrices alfanumeacutericasMatrices de punterosMatrices de matrices

sect44 Funciones

DeclaracioacutenDefinicioacutenArgumentos formales y actualesLlamada y conversioacuten de argumentosValores devueltos

sect45 Estructuras

Declaracioacuten de estructurasInicializacioacutenOperaciones permitidasAcceso a miembrosEstructuras y funcionesMatrices de estructurasPunteros a estructurasEstructuras auto-referenciadas

sect46 Campos de Bits

sect47 Uniones

sect48 Enumeraciones

Expresiones

Asociatividad y precedencia de operadoresOrden de evaluacioacutenErrores y desbordamientosExpresiones con coma

sect49 Operadores

AritmeacuteticosAsignacioacutenManejo de BitsOperador ComaCondicionalOp de igualdadOp LoacutegicosModelado de tiposOp de PreprocesoOp de punteroRelacionalessizeoftypeidOp primariosOp antildeadidosOp UnitariosSobrecarga de OperadoresOperador Operador newOperador delete

sect410 Sentencias

Sentencias de etiqueta case defaultSentencias de seleccioacuten if hellip else else if switchSentencias de iteracioacuten while dowhile forSentencias de salto break continue goto return

sect411 Clases

CreacioacutenDeclaracioacutenNombres de ClasesAacutembito de nombresInstanciado de Clasesthis (palabra reservada)Miembros estaacuteticosClases polimoacuterficasFunciones virtualesFunciones dinaacutemicasClases abstractas

sect412 Plantillas

Funciones geneacutericasClases geneacutericas

Aunque las secciones anteriores describen completamente el lenguaje desde una perspectiva formal hemos antildeadido un capiacutetulo adicional (sect413) dedicado a los tecnicismos En eacutel se incluyen algunos consejos y reglas de buena praacutectica para la programacioacuten C++ asiacute como algunos idioms

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

41 Declaraciones

sect1 Sinopsis

Una declaracioacuten es una claacuteusula que introduce nombres en una unidad de compilacioacuten ( 142) o redeclara nombres introducidos por declaraciones previas La norma sentildeala que una declaracioacuten especifica la interpretacioacuten y atributos de estos nombres (como tipo de enlazado y de almacenamiento si es un objeto) asiacute como las condiciones para que una declaracioacuten no sea

tambieacuten una definicioacuten En la paacutegina adjunta se muestra su gramaacutetica ( Gramaacutetica)

Cada una de las introducciones unitarias que puede existir en una declaracioacuten es un declarador (declarator) Asiacute pues un declarador introduce un nombre o redeclara uno

declarado previamente La paacutegina adjunta muestra su gramaacutetica ( Gramaacutetica)

El presente capiacutetulo repasa este importante concepto y otros relacionados tales como objetos clases de almacenamiento tipos aacutembitovisibilidad duracioacuten y enlazado

El aacutembito visibilidad duracioacuten y enlazado son propiedades o caracteriacutesticas 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 definicioacuten de declaracioacuten o la exposicioacuten de su sintaxis

En el epiacutegrafe 4111 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 tambieacuten es dada a conocer mediante una declaracioacuten

411 Entidades

sect1 Presentacioacuten

En relacioacuten con los conceptos que aquiacute nos incumben consideramos que una entidad ( 121) 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 objeto-valor

Un algoritmo con informacioacuten sobre manipulacioacuten de datos Lo denominamos entidad-algoritmo o simplemente algoritmo

Respecto a los objetos-valor una posible clasificacioacuten podriacutea dividirlos en las siguientes categoriacuteas

Agregados

o matrizo estructurao unioacuteno clase unioacuten

Funciones Escalares

o Aritmeacuteticoo Enumeracioacuteno Booleanoo Punteroo Referencia

void

void ( 221) es un tipo especial con un valor muy particular ausencia de valor Los escalares son de caracteriacutesticas tales que su valor no pueden ser descompuestos en partes maacutes pequentildeas

por ejemplo un entero un valor loacutegico (cierto-falso) etc Las funciones ( 44) son principalmente algoritmo ya que estaacuten asociadas a ciertas operaciones (cierta computacioacuten) pero por convencioacuten se les puede asignar un valor es el que devuelven (puede ser void) Por su parte los agregados comparten la caracteriacutestica de que su valor puede ser descompuesto en elementos maacutes simples (escalares)

sect2 El papel de las declaraciones

Haciendo un siacutemil social podriacuteamos decir que las declaraciones son las encargadas de presentar al compilador cualquier entidad que deba existir en el programa Son por tanto el Chambelaacuten de la sociedad C++ Como en el caso de las presentaciones sociales esta presentacioacuten no se reduce a indicar el nombre tambieacuten puede sentildealarse algunas caracteriacutesticas 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

sect3 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 expresioacuten compleja que

represente uniacutevocamente al objeto ( 211 ) Cualquier intento de utilizar una declaracioacuten sin un nombre es un error aunque el nombre no tiene que responder necesariamente a un objeto o funcioacuten Ejemplo

extern int Errorchar Errorchar cptr Ok cptr nombre de punteroclass C Ok C nombre de clasetypedef unsigned int UINT Ok UINT alias para un tipo conocido

Ademaacutes del identificador las declaraciones de funciones pueden incluir ciertos atributos inline ( 4112a) virtual ( 4118a) y explicit ( 4112d1)

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 ( 21 ) Entre otros puede incluir los siguientes char wchar_t bool short int long signed unsigned float double void

Relativos al tipo de almacenamiento Determina el sitio en que se guarda el objeto y su

duracioacuten ( 213 ) 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 disquisicioacuten respecto a si un mismo objeto Por ejemplo una variable puede estar referenciado por dos identificadores distintos (que se refieren a la misma regioacuten de memoria) En la mayoriacutea de lenguajes de programacioacuten esta distincioacuten entre identificador y almacenamiento estaacute perfectamente establecida y suelen proporcionar mecanismos sintaacutecticos para que dos identificadores puedan referirse al mismo almacenamiento

412 Declaraciones y definiciones

sect1 Sinopsis

Utilizando un leacutexico formalista podemos decir que una declaracioacuten es una sentencia que

introduce un nombre en una unidad de compilacioacuten ( 142) daacutendole existencia semaacutentica Esto de la existencia semaacutentica es una forma elegante de decir que a partir de ahiacute el compilador sabe que cosa es (representa) ese nombre La forma de darle existencia semaacutentica a las entidades es declararlos (algo asiacute como presentarlos formalmente en el coacutedigo) Por ejemplo si declaramos una variable x o una funcioacuten func a partir de ahiacute el compilador sabe que x es una variable de tal tipo y que func es una funcioacuten de caracteriacutesticas cuales

El punto importante a resaltar aquiacute es que cada declaracioacuten asocia un nombre con un tipo de dato

lo que en C++ (una sociedad muy clasista 22) es importante ya que el conocimiento del tipo que corresponde a un identificador proporciona al compilador mucha informacioacuten sobre la entidad

representada por este (en muchas ocasiones casi toda la informacioacuten necesaria ) En especial el compilador dispone de una amplia informacioacuten acerca del uso de los tipos baacutesicos que operaciones son permitidas y que significado tienen estas operaciones

No olvidar que una declaracioacuten no hace nada maacutes que esto Es decir no antildeade ninguna otra informacioacuten distinta de relacionar una etiqueta con un tipo Posteriormente cuando esta etiqueta esteacute asociada con una entidad concreta (con una zona de memoria) las operaciones permitidas se

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

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

sect31 Octal

Rango 0 a 377

Ejemplos0 Caraacutecter nulo (fin de cadena)

03 Ctr-C

07 Bell

013 Vertical TAB

077

sect32 Hexadecimal

Rango x00 a xFF

Ejemplos0 Caraacutecter nulo (fin de cadena)x3 Ctr-Cx7 BellxB Vertical TABx3F

sect4 Los nuacutemeros mayores que los indicados generan un error de compilacioacuten Numeric constant too large Por ejemplo el octal 777 es mayor que el maacuteximo permitido (377) por lo que produciriacutea un error El primer caraacutecter no octal o no hexadecimal que se encuentre en una secuencia octal o hexadecimal respectivamente sentildeala el final de la secuencia de escape Por ejemplo

printf(x0721Un Sistema Operativo)

La sentencia anterior deberiacutea ser interpretada como el hexadecimal x07 (BEL) y 21 Un Sistema Operativo aunque quizaacutes el compilador lo interprete como hexadecimal x072 (el caraacutecter r) y la cadena literal 1Un sistema Operativo Para evitar este tipo de ambiguumledades debe escribirse

printf(x07 21Un Sistema Operativo)

Tambieacuten pueden darse ambiguumledades si una secuencia de escape en octal es seguida por un nuacutemero no octal Por ejemplo dado que los diacutegitos 8 y 9 no son octales vaacutelidos la constante 258 puede ser interpretada como una constante de dos caracteres 25 (Ctrl-U) y un 8

sect5 Trigrafos

Con la extensioacuten de la informaacutetica a paiacuteses distintos del aacutembito anglosajoacuten 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 mayoriacutea de teclados en Espantildeol no existe la tilde ~ como un caraacutecter independiente lo que no es inconveniente para la escritura normal ya que la uacutenica ocurrencia en este signo en Espantildeol es en la letra entildee Ntilde que siacute dispone de su correspondiente tecla Pero la referida ausencia de la tilde como siacutembolo independiente resulta una molestia para los programadores ya que el fuente requiere en ocasiones incluir dicho siacutembolo Para resolver el problema se adoptoacute el convenio que estos caracteres conflictivos podiacutean representarse en el coacutedigo fuente mediante parejas y ternas de caracteres los denominados diacutegrafos y triacutegrafos que se muestran en la tabla adjunta

Triacutegrafo Caraacutecter Diacutegrafo = ( [ lt ) ] gt ^ lt lt gt gt | - ~

Nota la interpretacioacuten de estos triacutegrafos retarda considerablemente la accioacuten del compilador por lo que Borland C++ incluye un traductor especiacutefico el programa trigraphexe que puede traducir el coacutedigo fuente antes de la compilacioacuten [4]

Tema relacionado Representacioacuten expliacutecita de operadores loacutegicos ( 498)

323f Constantes de cadena

sect1 Sinopsis

Las constantes de cadena tambieacuten llamadas cadenas literales o alfanumeacutericas (String literals) son utilizadas para albergar secuencias de caracteres alfanumeacutericos y forman una categoriacutea especial dentro de las constantes aunque tambieacuten pueden ser consideradas un caso

especial de matrices de caracteres ( 434) Se representan en el fuente como una secuencia de caracteres entre comillas dobles ()

Esto es una cadena literalLEsto es una cadena de caracteres anchos

Vistas con cierta perspectiva las cadenas literales aparecen como un tipo algo extrantildeo que en cierta forma desentona del resto de entidades del universo C++ y que no deberiacutean tener cabida en eacutel En realidad hay algo de esto representan una herencia de su antecesor C en el que se utilizan estas extrantildeas construcciones para almacenar texto alfanumeacuterico en el que su punto final se identifica mediante el caraacutecter nulo [2]

El texto de una cadena literal puede contener cualquier caraacutecter del juego de caracteres

imprimibles ASCII ( 221a) Para representar los caracteres no imprimibles se utilizan las

denominadas secuencias de escape un truco que consiste en sustituir cada caraacutecter no imprimible por una secuencia de dos o tres caracteres Naturalmente una cadena literal no debe contener un caraacutecter nulo en su interior (que como hemos indicado sentildeala el final de la cadena) en caso contrario al aplicarse las funciones de Libreriacutea Estaacutendar claacutesicas (heredadas de C) el resultado es impredecible

sect11 El punto importante a entender aquiacute podriacutea sintetizarse en que desde la oacuteptica 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 atencioacuten a que el antiguo coacutedigo C sea compatible con los

compiladores C++

Si la cadena no estaacute precedida por la letra L es una matriz de caracteres tipo const char (

323) tambieacuten denominada cadena estrecha u ordinaria (Narrow string literal)

Si la cadena estaacute precedida por la letra L los miembros de la matriz son caracteres anchos

( 221a1) del tipo const w_char y se denomina cadena ancha (Wide string literal)

Estos objetos tienen almacenamiento estaacutetico en el sentido indicado en 226 es decir que el compilador conoce los valores en tiempo de compilacioacuten y que probablemente sean

guardados en el segmento ( 132) [4]

sect12 Generalmente aparecen a la derecha en expresiones de asignacioacuten o como paraacutemetros de funciones pueden aparecer incluso como valores devueltos por funciones Ejemplos

char ptr = Hola mundoprintf(sn Soy una cadena literal)cout ltlt acabo de llegar ltlt endlreturn Se termina la funcioacuten

sect2 Secuencias de escape

Dentro de las comillas se pueden representar caracteres especiales (no imprimibles)

mediante secuencias de escape ( 323e) Por ejemplo el coacutedigo

ttNombretDireccioacutennn

Se representa como

Nombre Direccioacuten

Nombre es precedido por dos tabulaciones Direccioacuten esta precedido por una tabulacioacuten La liacutenea va seguida de dos nueva liacutenea (NL) La secuencia proporciona las comillas interiores Si se

compila con la opcioacuten -A para compatibilidad ANSI la secuencia de escape es traducida por el compilador a

sect3 Como hemos sentildealado en C++ las cadenas alfanumeacutericas son teacutecnicamente matrices de caracteres constantes se almacenan internamente como secuencias de caracteres maacutes un caraacutecter final nulo 0 lo que significa que el almacenamiento usado es igual a la longitud visible de la cadena mas uno Seguacuten esto la cadena nula es almacenada como un solo caraacutecter 0 y no hay maacutes liacutemite que la memoria disponible para la longitud posible de una cadena Por ejemplo la cadena Holan se guarda internamente como

H o l a n 0

Nota histoacuterica El meacutetodo de identificar el final de cadena mediante un caraacutecter nulo es ineficiente y aparte de que no permite utilizar cadenas que contengan un caraacutecter nulo en su interior (por ejemplo ficheros binarios) su manejo conlleva problemas de rendimiento [3]

Aparentemente la razoacuten por la que C y C++ utilizan este meacutetodo se debe a que C se desarrolloacute

sobre maacutequinas Unix ( 1 ) y a su vez este sistema operativo fue desarrollado inicialmente sobre una maacutequina DEC (Digital Equipment Corporation) PDP-7 que teniacutean un tipo de dato denominado ASICZ (ASCII con un Zero al final) que era directamente reconocible por su ensamblador

sect4 Peculiaridades

En el preaacutembulo sentildealamos 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 ninguacuten 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 uacutenica singularidad es que el compilador C++ les permite ciertas formas particulares de definicioacuten y declaracioacuten que les confiere cierta personalidad

Por ejemplo el hecho de inicializarlas directamente con expresiones como las sentildealadas sect12 o que antildeada automaacuteticamente el caraacutecter nulo de terminacioacuten a los caracteres expliacutecitamente indicados por el programador

Respecto a esto uacuteltimo solo tiene justificacioacuten histoacuterica porque el caraacutecter nulo se utilizaba en las antiguas funciones de libreriacutea para indicar el final de la cadena Por esta razoacuten aunque es posible incluir caracteres nulos dentro de las cadenas literales Por ejemplo Hola0 mundo no estaacute garantizado que funcione en todos los casos (seraacute malinterpretado por las funciones printf strcpy y strlen de la Libreriacutea Estaacutendar)

Ejemplo

char ptr = Hola0 mundoprintf(sn ptr)

Salida

Hola

sect5 Una cadena nula (vaciacutea) se representa o 0 tiene un solo caraacutecter el caraacutecter nulo (ver a continuacioacuten) Observe que desde el punto de vista del Rvalue la constante de cadena A es A

0 mientras que la constante caraacutecter ( 323d) A es A

Se considera que la longitud de un NTBS es el nuacutemero de caracteres que preceden al de terminacioacuten de forma que la cadena nula tiene longitud 0 (aunque en realidad contiene un caraacutecter) Sin embargo el valor de la cadena incluye el caraacutecter de final

Conviene no confundir una constante de cadena (matriz) de un solo caraacutecter con un

caraacutecter char constante ( 323d) o variable ( 221a) La cadena de un solo caraacutecter es necesariamente la cadena nula su uacutenico elemento es el de fin de cadena Ejemplo

char x1= a L1 variable x1 tipo char valor == ASCII a == 97 decimalconst char x2= a L2 constante x2 tipo const charchar x3 = a L3 variable x3 tipo puntero-a-char sentildeala a cadena de dos caracteres 97 y 0 decimalconst char x4 = a L4 variable x4 tipo puntero a constante caraacutecterchar x5[1]= a L5 variable x5 tipo matriz de un caraacutecter valor x[0]== a == 97 decimal

Los objetos representados por los Rvalues ( 215) de las expresiones anteriores son de distinto tipo y se almacenan con tamantildeos distintos La primera segunda y quinta son constantes caraacutecter (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 tambieacuten muy importante sentildealar que la asignacioacuten

str = AEIOU

solo es posible si str se ha declarado previamente como puntero a caraacutecter es decir

char str sectg

Aunque se puede declarar y definir en la misma sentencia (preferible)

char str = AEIOU secth

El lector observador advertiraacute en la expresioacuten anterior una evidente inconsistencia en la gramaacutetica del C++ En efecto como se ha sentildealado las cadenas literales son de caracteres constantes En

consecuencia no asignables a punteros tales como los definidos en sectg o secth teacutecnicamente punteros a caraacutecter Teoacutericamente solo hubiese sido aceptable la asignacioacuten a puntero-a-caraacutecter-constante tal como

const char str = AEIOU secti

ya que un puntero-a-constante-tipoX no es intercambiable por un puntero-a-tipoX ( 421a) La razoacuten de esta inconsistencia en la definicioacuten de las cadenas literales hay que buscarla en otra de las desafortunadas herencias del C claacutesico y en la necesidad de mantener compatibilidad con millones de liacuteneas de coacutedigo existente En C y en las primitivas versiones de C++ las cadenas literales eran consideradas como de tipo char (puntero a caraacutecter)

Aunque la mayoriacutea de compiladores C++ permiten este tipo de sentencias por razones de tipo histoacuterico parece que tal permisividad tiende a ser deprecated (a extinguir) de forma que las uacuteltimas revisiones de algunos compiladores pueden lanzar una advertencia o error en tales circunstancias La forma canoacutenica de definir este tipo de cadenas seriacutea

const char str[] = AEIOU

La expresioacuten secth define una matriz de seis caracteres constantes (almacenado en alguacuten sitio) que no tiene identificador simple (nombre) Tambieacuten define un puntero str al primer elemento de la matriz (maacutes formalmente es un puntero a caraacutecter) Por tanto a falta de un nombre la matriz tiene que ser accedida a traveacutes del puntero (que tendraacute que ser tratado como tal -puntero-) Sin embargo las expresiones

char arr[] = AEIOU sectjchar arr[6] = AEIOUchar arr[6] = AEIOU0char arr[6] = AEIOUchar arr[6] = AEIOU0

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 (secth ) str es un puntero un objeto que puede ser usado con el aacutelgebra de punteros Por ejemplo es vaacutelida la expresioacuten str++ que

equivale a str = str+1 En los otros cinco casos (sectj ) arr es un nemoacutenico que representa una matriz y la expresioacuten arr++ que equivale a arr = arr+1 es ilegal El operando arr+1 es tratado como (amparr[0])+1 lo que es correcto (a un puntero se le puede sumar un entero) La asignacioacuten no seriacutea correcta porque intentariacutea asignar el puntero amparr[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 asignacioacuten 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 asignacioacuten del tipo x = aeiou Si tiene en cambio poderosas funciones en su Libreriacutea Estaacutendar para hacer todo tipo de manipulaciones con cadenas alfanumeacutericas

Es tambieacuten importante distinguir otra diferencia entre las expresiones

char a1[6] = AEIOU0 p1 = ampa1[0]char a2 = AEIOU

Ambas producen matrices de caracteres absolutamente ideacutenticos en contenido y tamantildeo pero a1 es una matriz por lo que sus elementos podriacutean ser alterados usando el identificador Por ejemplo es vaacutelido a1[1]= e o su equivalente (p1+1)=e En cambio un intento anaacutelogo sobre el segundo obliga a usar necesariamente la versioacuten con puntero (a2+1)=e Ademaacutes de que por las razones ya expuestas [2] el resultado no estaacute 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 todaviacutea la asignacioacuten

a2 = aeiou

En este caso el compilador almacena en alguacuten sitio la cadena aeiou0 y asigna a a2 la direccioacuten 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 ninguacuten modo aunque sigue malgastando espacio de memoria

Tambieacuten es posible declarar cadenas de caracteres anchos con el prefijo L como en el ejemplo

wchar_t wptr = Laeiou

en este caso wptr sentildeala una cadena de caracteres anchos ( 221a1) la cadena es del tipo const wchar_t

Para saber la longitud de una constante literal es necesario que el programa repase la cadena hasta encontrar el caraacutecter de fin de cadena lo que se consigue con la funcioacuten de libreriacutea strlen (incluida en la cabecera estaacutendar ltstringhgt) que proporciona la longitud sin contar el caraacutecter final

sect6 Concatenacioacuten de cadenas

Las cadenas literales adyacentes separadas solo por un especio son automaacuteticamente

concatenadas durante la fase de preprocesado ( 141) de la compilacioacuten Por ejemplo Hola mundo es equivalente a Hola mundo Tambieacuten puede usarse la barra invertida ( ) como siacutembolo de continuacioacuten para extender una cadena literal maacutes allaacute del liacutemite de una liacutenea

puts(En realidad esto es una cadena de una linea)char p = Esto es en otra cadena tambieacuten de una sola liacutenea

La concatenacioacuten suprime el caraacutecter nulo de final en las cadenas intermedias y mantiene el de la uacuteltima Esta operacioacuten no altera el significado de los caracteres que intervienen en las cadenas concatenadas Por ejemplo la concatenacioacuten

xA B

Produce la cadena

xAB

que tiene tres caracteres el hexadecimal xA el caraacutecter B y el caracter final nulo 0 En vez del caraacutecter hexadecimal xAB

La concatenacioacuten de cadenas anchas y estrechas tiene resultados impredecibles

323g Constantes de enumeracioacuten

sect1 Sinopsis

Existe un tipo especial de variables denominadas variables enumeradas o

simplemente enumeraciones ( 48 ) Se caracterizan por poder adoptar valores entre una seleccioacuten de constantes enteras denominadas enumeradores cuyos valores son establecidos en el momento de la declaracioacuten del nuevo tipo Como se ha sentildealado son enteros y (una vez establecidos) de valor constante razoacuten por la que se los denomina tambieacuten constantes de enumeracioacuten

Ejemplo

enum estado MALO =0 REGULAR =1 BUENO =2 EXTRA =3

La sentencia anterior declara estado como un tipo de variable de enumeracioacuten Los miembros de esta clase pueden adoptar los valores indicados y son representados por los nemoacutenicos MALO REGULAR BUENO y EXTRA Estas cuatro constantes son los enumeradores del nuevo tipo

Como advertencia a lo indicado hasta aquiacute no confundir la enumeracioacuten (la variable) con los enumeradores (las constantes enteras que delimitan el conjunto de valores posibles de la variable) Tambieacuten 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 = EXTRAestado tu_estado = REGULAR stdcout ltlt Mi estado actual es ltlt mi_estado ltlt endl -gt Mi estado actual es 3

En el caso anterior estado es una enumeracioacuten (tipo geneacuterico) 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 (geneacuterico) con un tipo enum concreto una instancia (variable enumerada) de ese tipo ni con los valores concretos (constantes de enumeracioacuten) que puede adoptar

Para facilitar la legibilidad los identificadores de las constantes de enumeracioacuten son nemoacutenicos y sus nombres suelen estar en mayuacutesculas debido a una larga tradicioacuten CC++ de representar de este modo las constantes

Ya hemos sentildealado que estas constantes (enumeradores) son de tipo entero por lo que pueden ser utilizadas en cualquier expresioacuten donde sean permitidas las constantes enteras Sus identificadores deben ser uacutenicos dentro del aacutembito de la declaracioacuten enum Se permiten inicializadores negativos los valores que adoptan los enumeradores suelen ser uacutenicos (aunque se permiten duplicidades) Para una visioacuten maacutes detallada de las declaraciones de estas constantes

ver enumeraciones ( 48 ) y la explicacioacuten que sigue sobre la palabra clave enum

sect2 Sintaxis

enum [ltnombre-de-tipogt] ltnombr-constgt [= ltvalorgt] [lista_var]

Puede omitirse la palabra clave enum siempre que el nemoacutenico ltnombre-de-tipogt no sea empleado para nada maacutes en el mismo aacutembito Ejemplo

calidad BUENA REGULAR MALA

En este caso el compilador presupone que calidad es un enumerador y no debe existir otra

definicioacuten en el mismo aacutembito de nombres En otras palabras calidad no debe utilizarse en el mismo aacutembito para designar otro objeto

ltnombre-de-tipogt es una etiqueta opcional que identifica al conjunto Puede omitirse si no se va a usar ninguna otra variable de este tipo de enumeracioacuten Ejemplo

enum CIERTO DUDOSO FALSO

ltnombr-constgt es el nombre de la constante de enumeracioacuten (enumerador) a la que opcionalmente puede asignarse el valor definido porltvalorgt En el ejemplo anterior son tres CIERTO DUDOSO y FALSO

ltvalorgt debe ser un entero (ya se ha sentildealado que los enumeradores son constantes

enteras) Si no se especifica ninguacuten valor se supone que es ltpreviogt + 1 donde ltpreviogt es el valor del enumerador anterior de la lista (el valor por defecto para el primero es cero) ltvalorgtpuede ser cualquier expresioacuten que resulte en un entero positivo o negativo (despueacutes de posible conversioacuten a entero)

ltlista_vargt 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 enumeracioacuten de nombre geneacuterico calidad las variables de este tipo pueden adoptar tres valores 0 1 y 2 identificados respectivamente por los nemoacutenicos BUENO REGULAR y MALO ademaacutes se definen dos variables del nuevo

tipo nota yestado

enum calidad BUENO REGULAR MALO nota estado

sect3 Descripcioacuten

La palabra clave enum define una enumeracioacuten 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 nemoacutenicos Por ejemplo la declaracioacuten

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 nemoacutenicos DOM LUNSAB Ademaacutes 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 nemoacutenicos ULT BW40 C40 BW80 C80 y MONO

Los valores asignados a los enumeradores dependen del formato de la declaracioacuten 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 Ademaacutes como puede comprobarse las expresiones de inicializacioacuten pueden incluir enumeradores previamente declarados

Los valores de los enumeradores no tienen porqueacute ser uacutenicos como en el ejemplo que sigue

enum estado BUENO MALO = 1 REGULAR = 1

326 Puntuadores

sect1 Sinopsis

Los signos de puntuacioacuten del lenguaje C++ juegan el mismo papel que sus homoacutenimos en el lenguaje natural escrito Conocidos tambieacuten comopuntuadores [1] son los que se citan a continuacioacuten La mayoriacutea de ellos tienen un doble uso y en ocasiones funcionan tambieacuten

comooperadores ( 49)

[ ] ( ) = ^ amp ndash + | ~ lt gt

sect2 Corchetes [ ]

Los corchetes indican subiacutendices de matrices uni y multi dimensionales

char ch str[] = Cadena de caracteresint mat[3][4] Matriz de 3 x 4ch = str[3] cuarto elemento

sect3 Pareacutentesis ( )

Los pareacutentesis sirven para agrupar expresiones alterar la precedencia normal de los operadores y su asociatividad aislar expresiones condicionales indicar llamadas a funciones y sentildealar los paraacutemetros de estas La sintaxis de C++ exige indefectiblemente el uso de pareacutentesis en muacuteltiples ocasiones En los ejemplos que siguen se muestran algunos usos

d = c (a + b) modifica la precedencia normalif (d == z) ++x imprescindible en la sentencia iffor (x =1 xlt10 x++) imprescindible en la sentencia forfunc() sentildeala llamada a funcioacutenint func() declara funcioacutenint (fptr)() declara puntero a funcioacutenfptr = func asigna valor al puntero

Observe que en el uacuteltimo caso la ausencia de pareacutentesis equivale a ampfunc ( 424a )

Se recomienda el uso de pareacutentesis en las macro-definiciones para evitar problemas potenciales en la expansioacuten Por ejemplo

define CUBO(x) ((x) (x) (x))

sect4 Llaves

Los pares de llaves sentildealan el comienzo y final de una sentencia compuesta es decir bloques de coacutedigo (grupos de sentencias que son tratadas como una unidad) Constituyen el segundo paso (despueacutes de las sentencias) en la estructuracioacuten y compartimentacioacuten del coacutedigo C++

if (d == z) ++x func()

Un bloque es una sentencia compuesta se trata de una sucesioacuten (que puede estar vaciacutea) de sentencias delimitadas por un par de corchetes Desde el punto de vista sintaacutectico un bloque puede ser considerado como una sola sentencia Juega un papel importante en el aacutembito (scope) de los identificadores puesto que un identificador declarado dentro de un bloque tiene un aacutembito

que comienza en el punto de la declaracioacuten 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)

Despueacutes del corchete de cierre no se necesita el punto y coma de fin de sentencia

if (statement) punto y coma ilegal else

Nota las llaves sirven tambieacuten en C++ para otros usos distintos de la pura delimitacioacuten de bloques de coacutedigo Por ejemplo en la definicioacuten de estructuras uniones y clases en cuyo caso si puede ser necesaria la inclusioacuten del punto y coma despueacutes de la llave de cierre

sect5 Coma

La coma como puntuador se utiliza para separar los elementos en las listas de paraacutemetros de una funcioacuten

void func(int n float f char ch)

La coma se usa tambieacuten como un operador en las expresiones con coma ( 4105) Es posible mezclar los dos usos (separador en lista de paraacutemetros y operador) pero deben usarse pareacutentesis para distinguirlos

sect6 Punto y coma

El punto y coma es el signo de fin de sentencia Cualquier expresioacuten legal C++ terminada por un punto y coma (incluyendo la expresioacuten vaciacutea - un punto y coma aislado-) es interpretado como una

sentencia conocidas como sentencia-expresioacuten ( 410) La expresioacuten se evaluacutea y el resultado se descarta si no tiene efectos colaterales C++ la ignora

a + b evaluacutea a + b descarta el resultado++a efecto lateral en a se descarta el valor ++a expresioacuten vaciacutea = sentencia nula

El punto y coma se usa a veces para crear sentencias nulas

for (i = 0 i lt n i++) sentencia nula (hacer nada)

sect7 Dos puntos

Los dos puntos se utilizan para sentildealar sentencias etiquetadas ( 4101)

comienzo x=0 comienzo es la etiquetagoto comienzo

sect8 Puntos suspensivos

Los puntos suspensivos tambieacuten 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 nuacutemero variable de argumentos o pueden ser de tipo variable ( 441) Por ejemplo

void func(int n char ch)

Este prototipo de funcioacuten declara que func estaacute definida de modo que debe ser llamada con al

menos dos argumentos un int y un char Ademaacutes puede tener un cierto nuacutemero de argumentos adicionales (puede omitirse la coma antes de la elipsis)

Se utiliza tambieacuten para indicar que un manejador de excepciones (handler) puede capturar una

excepcioacuten de cualquier tipo ( 162) Ejemplo

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

Nota como podeacuteis ver en ocasiones mi uso particular en los ejemplos de los tres puntos es para indicar cualquier nuacutemero de sentencias Espero que no sea motivo de confusioacuten Desde luego en el caso anterior seriacutea maacutes correcta la notacioacuten

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

sect9 Asterisco

El asterisco puede ser utilizado en C++ de tres formas como una declaracioacuten de tipo de variable

(variable de puntero 42 ) como operador de indireccioacuten (tambieacuten llamado operador

de dereferencia 4911a) y como operador de multiplicacioacuten

Ejemplos

char char_ptr declara puntero a caraacutecterx = int_ptr operador de indireccioacutenl = 2 314 r operador multiplicacioacuten

sect10 Signo igual =

El signo igual = separa la declaracioacuten de variables de las listas de inicializacioacuten

char array[5] = 1 2 3 4 5

Recordemos que al contrario que en C donde las declaraciones no pueden estar precedidas por ninguacuten coacutedigo deben ir al principio en C++ las declaraciones de cualquier tipo pueden aparecer en cualquier punto del coacutedigo (con algunas restricciones)

En la lista de argumentos de una funcioacuten el signo igual indica el valor por defecto para un paraacutemetro

int f(int i = 0) el valor por defecto de k es cero

El signo igual es tambieacuten utilizado como operador de asignacioacuten ( 492) Ejemplo

x = yz += 5

sect11 Almohadilla

Si la almohadilla aparecen en el primer caraacutecter (distinto de espacio en blanco) de una liacutenea

sentildeala directivas de preproceso ( 4910) En este caso es un operador especiacutefico de la fase

de preproceso del coacutedigo fuente Significa una opcioacuten del preprocesador ( 14) que no tiene porqueacute estar asociada necesariamente a generacioacuten de coacutedigo Las directivas se situacutean generalmente al comienzo del programa aunque legalmente pueden aparecer en cualquier punto

Ejemplos de directivas de preproceso

(null directive)define NULO 0include ltstdiohgt

4 Estructura del lenguaje

sect1 Sinopsis

Esta parte proporciona una definicioacuten formal del lenguaje C++ describiendo las formas en que

pueden agruparse correctamente los tokens ( 32) palabras que constituyen el lenguaje entendible por el compilador para formar declaraciones expresiones y otras unidades significativas Para su anaacutelisis lo hemos descompuesto en 13 grupos seguacuten la clasificacioacuten que sigue

sect41 Declaraciones

ObjetosReferencias amp definicionesDefinicioacuten provisionalAacutembitoVisibilidadDuracioacutenUnidad de compilacioacutenEnlazado

Sintaxis de declaraciones

Conversiones aritmeacuteticasInicializacioacutenEspecificadores de clase de almacenamientoModificadores auxiliaresModificadores de funcioacuten

sect42 Punteros

Puntero a objetoDeclaracioacuten de punterosAritmeacutetica de punterosReferenciasPuntero a funcioacuten

sect43 Matrices

Declaracioacuten de matricesMatrices alfanumeacutericasMatrices de punterosMatrices de matrices

sect44 Funciones

DeclaracioacutenDefinicioacutenArgumentos formales y actualesLlamada y conversioacuten de argumentosValores devueltos

sect45 Estructuras

Declaracioacuten de estructurasInicializacioacutenOperaciones permitidasAcceso a miembrosEstructuras y funcionesMatrices de estructurasPunteros a estructurasEstructuras auto-referenciadas

sect46 Campos de Bits

sect47 Uniones

sect48 Enumeraciones

Expresiones

Asociatividad y precedencia de operadoresOrden de evaluacioacutenErrores y desbordamientosExpresiones con coma

sect49 Operadores

AritmeacuteticosAsignacioacutenManejo de BitsOperador ComaCondicionalOp de igualdadOp LoacutegicosModelado de tiposOp de PreprocesoOp de punteroRelacionalessizeoftypeidOp primariosOp antildeadidosOp UnitariosSobrecarga de OperadoresOperador Operador newOperador delete

sect410 Sentencias

Sentencias de etiqueta case defaultSentencias de seleccioacuten if hellip else else if switchSentencias de iteracioacuten while dowhile forSentencias de salto break continue goto return

sect411 Clases

CreacioacutenDeclaracioacutenNombres de ClasesAacutembito de nombresInstanciado de Clasesthis (palabra reservada)Miembros estaacuteticosClases polimoacuterficasFunciones virtualesFunciones dinaacutemicasClases abstractas

sect412 Plantillas

Funciones geneacutericasClases geneacutericas

Aunque las secciones anteriores describen completamente el lenguaje desde una perspectiva formal hemos antildeadido un capiacutetulo adicional (sect413) dedicado a los tecnicismos En eacutel se incluyen algunos consejos y reglas de buena praacutectica para la programacioacuten C++ asiacute como algunos idioms

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

41 Declaraciones

sect1 Sinopsis

Una declaracioacuten es una claacuteusula que introduce nombres en una unidad de compilacioacuten ( 142) o redeclara nombres introducidos por declaraciones previas La norma sentildeala que una declaracioacuten especifica la interpretacioacuten y atributos de estos nombres (como tipo de enlazado y de almacenamiento si es un objeto) asiacute como las condiciones para que una declaracioacuten no sea

tambieacuten una definicioacuten En la paacutegina adjunta se muestra su gramaacutetica ( Gramaacutetica)

Cada una de las introducciones unitarias que puede existir en una declaracioacuten es un declarador (declarator) Asiacute pues un declarador introduce un nombre o redeclara uno

declarado previamente La paacutegina adjunta muestra su gramaacutetica ( Gramaacutetica)

El presente capiacutetulo repasa este importante concepto y otros relacionados tales como objetos clases de almacenamiento tipos aacutembitovisibilidad duracioacuten y enlazado

El aacutembito visibilidad duracioacuten y enlazado son propiedades o caracteriacutesticas 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 definicioacuten de declaracioacuten o la exposicioacuten de su sintaxis

En el epiacutegrafe 4111 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 tambieacuten es dada a conocer mediante una declaracioacuten

411 Entidades

sect1 Presentacioacuten

En relacioacuten con los conceptos que aquiacute nos incumben consideramos que una entidad ( 121) 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 objeto-valor

Un algoritmo con informacioacuten sobre manipulacioacuten de datos Lo denominamos entidad-algoritmo o simplemente algoritmo

Respecto a los objetos-valor una posible clasificacioacuten podriacutea dividirlos en las siguientes categoriacuteas

Agregados

o matrizo estructurao unioacuteno clase unioacuten

Funciones Escalares

o Aritmeacuteticoo Enumeracioacuteno Booleanoo Punteroo Referencia

void

void ( 221) es un tipo especial con un valor muy particular ausencia de valor Los escalares son de caracteriacutesticas tales que su valor no pueden ser descompuestos en partes maacutes pequentildeas

por ejemplo un entero un valor loacutegico (cierto-falso) etc Las funciones ( 44) son principalmente algoritmo ya que estaacuten asociadas a ciertas operaciones (cierta computacioacuten) pero por convencioacuten se les puede asignar un valor es el que devuelven (puede ser void) Por su parte los agregados comparten la caracteriacutestica de que su valor puede ser descompuesto en elementos maacutes simples (escalares)

sect2 El papel de las declaraciones

Haciendo un siacutemil social podriacuteamos decir que las declaraciones son las encargadas de presentar al compilador cualquier entidad que deba existir en el programa Son por tanto el Chambelaacuten de la sociedad C++ Como en el caso de las presentaciones sociales esta presentacioacuten no se reduce a indicar el nombre tambieacuten puede sentildealarse algunas caracteriacutesticas 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

sect3 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 expresioacuten compleja que

represente uniacutevocamente al objeto ( 211 ) Cualquier intento de utilizar una declaracioacuten sin un nombre es un error aunque el nombre no tiene que responder necesariamente a un objeto o funcioacuten Ejemplo

extern int Errorchar Errorchar cptr Ok cptr nombre de punteroclass C Ok C nombre de clasetypedef unsigned int UINT Ok UINT alias para un tipo conocido

Ademaacutes del identificador las declaraciones de funciones pueden incluir ciertos atributos inline ( 4112a) virtual ( 4118a) y explicit ( 4112d1)

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 ( 21 ) Entre otros puede incluir los siguientes char wchar_t bool short int long signed unsigned float double void

Relativos al tipo de almacenamiento Determina el sitio en que se guarda el objeto y su

duracioacuten ( 213 ) 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 disquisicioacuten respecto a si un mismo objeto Por ejemplo una variable puede estar referenciado por dos identificadores distintos (que se refieren a la misma regioacuten de memoria) En la mayoriacutea de lenguajes de programacioacuten esta distincioacuten entre identificador y almacenamiento estaacute perfectamente establecida y suelen proporcionar mecanismos sintaacutecticos para que dos identificadores puedan referirse al mismo almacenamiento

412 Declaraciones y definiciones

sect1 Sinopsis

Utilizando un leacutexico formalista podemos decir que una declaracioacuten es una sentencia que

introduce un nombre en una unidad de compilacioacuten ( 142) daacutendole existencia semaacutentica Esto de la existencia semaacutentica es una forma elegante de decir que a partir de ahiacute el compilador sabe que cosa es (representa) ese nombre La forma de darle existencia semaacutentica a las entidades es declararlos (algo asiacute como presentarlos formalmente en el coacutedigo) Por ejemplo si declaramos una variable x o una funcioacuten func a partir de ahiacute el compilador sabe que x es una variable de tal tipo y que func es una funcioacuten de caracteriacutesticas cuales

El punto importante a resaltar aquiacute es que cada declaracioacuten asocia un nombre con un tipo de dato

lo que en C++ (una sociedad muy clasista 22) es importante ya que el conocimiento del tipo que corresponde a un identificador proporciona al compilador mucha informacioacuten sobre la entidad

representada por este (en muchas ocasiones casi toda la informacioacuten necesaria ) En especial el compilador dispone de una amplia informacioacuten acerca del uso de los tipos baacutesicos que operaciones son permitidas y que significado tienen estas operaciones

No olvidar que una declaracioacuten no hace nada maacutes que esto Es decir no antildeade ninguna otra informacioacuten distinta de relacionar una etiqueta con un tipo Posteriormente cuando esta etiqueta esteacute asociada con una entidad concreta (con una zona de memoria) las operaciones permitidas se

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

sect5 Trigrafos

Con la extensioacuten de la informaacutetica a paiacuteses distintos del aacutembito anglosajoacuten 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 mayoriacutea de teclados en Espantildeol no existe la tilde ~ como un caraacutecter independiente lo que no es inconveniente para la escritura normal ya que la uacutenica ocurrencia en este signo en Espantildeol es en la letra entildee Ntilde que siacute dispone de su correspondiente tecla Pero la referida ausencia de la tilde como siacutembolo independiente resulta una molestia para los programadores ya que el fuente requiere en ocasiones incluir dicho siacutembolo Para resolver el problema se adoptoacute el convenio que estos caracteres conflictivos podiacutean representarse en el coacutedigo fuente mediante parejas y ternas de caracteres los denominados diacutegrafos y triacutegrafos que se muestran en la tabla adjunta

Triacutegrafo Caraacutecter Diacutegrafo = ( [ lt ) ] gt ^ lt lt gt gt | - ~

Nota la interpretacioacuten de estos triacutegrafos retarda considerablemente la accioacuten del compilador por lo que Borland C++ incluye un traductor especiacutefico el programa trigraphexe que puede traducir el coacutedigo fuente antes de la compilacioacuten [4]

Tema relacionado Representacioacuten expliacutecita de operadores loacutegicos ( 498)

323f Constantes de cadena

sect1 Sinopsis

Las constantes de cadena tambieacuten llamadas cadenas literales o alfanumeacutericas (String literals) son utilizadas para albergar secuencias de caracteres alfanumeacutericos y forman una categoriacutea especial dentro de las constantes aunque tambieacuten pueden ser consideradas un caso

especial de matrices de caracteres ( 434) Se representan en el fuente como una secuencia de caracteres entre comillas dobles ()

Esto es una cadena literalLEsto es una cadena de caracteres anchos

Vistas con cierta perspectiva las cadenas literales aparecen como un tipo algo extrantildeo que en cierta forma desentona del resto de entidades del universo C++ y que no deberiacutean tener cabida en eacutel En realidad hay algo de esto representan una herencia de su antecesor C en el que se utilizan estas extrantildeas construcciones para almacenar texto alfanumeacuterico en el que su punto final se identifica mediante el caraacutecter nulo [2]

El texto de una cadena literal puede contener cualquier caraacutecter del juego de caracteres

imprimibles ASCII ( 221a) Para representar los caracteres no imprimibles se utilizan las

denominadas secuencias de escape un truco que consiste en sustituir cada caraacutecter no imprimible por una secuencia de dos o tres caracteres Naturalmente una cadena literal no debe contener un caraacutecter nulo en su interior (que como hemos indicado sentildeala el final de la cadena) en caso contrario al aplicarse las funciones de Libreriacutea Estaacutendar claacutesicas (heredadas de C) el resultado es impredecible

sect11 El punto importante a entender aquiacute podriacutea sintetizarse en que desde la oacuteptica 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 atencioacuten a que el antiguo coacutedigo C sea compatible con los

compiladores C++

Si la cadena no estaacute precedida por la letra L es una matriz de caracteres tipo const char (

323) tambieacuten denominada cadena estrecha u ordinaria (Narrow string literal)

Si la cadena estaacute precedida por la letra L los miembros de la matriz son caracteres anchos

( 221a1) del tipo const w_char y se denomina cadena ancha (Wide string literal)

Estos objetos tienen almacenamiento estaacutetico en el sentido indicado en 226 es decir que el compilador conoce los valores en tiempo de compilacioacuten y que probablemente sean

guardados en el segmento ( 132) [4]

sect12 Generalmente aparecen a la derecha en expresiones de asignacioacuten o como paraacutemetros de funciones pueden aparecer incluso como valores devueltos por funciones Ejemplos

char ptr = Hola mundoprintf(sn Soy una cadena literal)cout ltlt acabo de llegar ltlt endlreturn Se termina la funcioacuten

sect2 Secuencias de escape

Dentro de las comillas se pueden representar caracteres especiales (no imprimibles)

mediante secuencias de escape ( 323e) Por ejemplo el coacutedigo

ttNombretDireccioacutennn

Se representa como

Nombre Direccioacuten

Nombre es precedido por dos tabulaciones Direccioacuten esta precedido por una tabulacioacuten La liacutenea va seguida de dos nueva liacutenea (NL) La secuencia proporciona las comillas interiores Si se

compila con la opcioacuten -A para compatibilidad ANSI la secuencia de escape es traducida por el compilador a

sect3 Como hemos sentildealado en C++ las cadenas alfanumeacutericas son teacutecnicamente matrices de caracteres constantes se almacenan internamente como secuencias de caracteres maacutes un caraacutecter final nulo 0 lo que significa que el almacenamiento usado es igual a la longitud visible de la cadena mas uno Seguacuten esto la cadena nula es almacenada como un solo caraacutecter 0 y no hay maacutes liacutemite que la memoria disponible para la longitud posible de una cadena Por ejemplo la cadena Holan se guarda internamente como

H o l a n 0

Nota histoacuterica El meacutetodo de identificar el final de cadena mediante un caraacutecter nulo es ineficiente y aparte de que no permite utilizar cadenas que contengan un caraacutecter nulo en su interior (por ejemplo ficheros binarios) su manejo conlleva problemas de rendimiento [3]

Aparentemente la razoacuten por la que C y C++ utilizan este meacutetodo se debe a que C se desarrolloacute

sobre maacutequinas Unix ( 1 ) y a su vez este sistema operativo fue desarrollado inicialmente sobre una maacutequina DEC (Digital Equipment Corporation) PDP-7 que teniacutean un tipo de dato denominado ASICZ (ASCII con un Zero al final) que era directamente reconocible por su ensamblador

sect4 Peculiaridades

En el preaacutembulo sentildealamos 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 ninguacuten 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 uacutenica singularidad es que el compilador C++ les permite ciertas formas particulares de definicioacuten y declaracioacuten que les confiere cierta personalidad

Por ejemplo el hecho de inicializarlas directamente con expresiones como las sentildealadas sect12 o que antildeada automaacuteticamente el caraacutecter nulo de terminacioacuten a los caracteres expliacutecitamente indicados por el programador

Respecto a esto uacuteltimo solo tiene justificacioacuten histoacuterica porque el caraacutecter nulo se utilizaba en las antiguas funciones de libreriacutea para indicar el final de la cadena Por esta razoacuten aunque es posible incluir caracteres nulos dentro de las cadenas literales Por ejemplo Hola0 mundo no estaacute garantizado que funcione en todos los casos (seraacute malinterpretado por las funciones printf strcpy y strlen de la Libreriacutea Estaacutendar)

Ejemplo

char ptr = Hola0 mundoprintf(sn ptr)

Salida

Hola

sect5 Una cadena nula (vaciacutea) se representa o 0 tiene un solo caraacutecter el caraacutecter nulo (ver a continuacioacuten) Observe que desde el punto de vista del Rvalue la constante de cadena A es A

0 mientras que la constante caraacutecter ( 323d) A es A

Se considera que la longitud de un NTBS es el nuacutemero de caracteres que preceden al de terminacioacuten de forma que la cadena nula tiene longitud 0 (aunque en realidad contiene un caraacutecter) Sin embargo el valor de la cadena incluye el caraacutecter de final

Conviene no confundir una constante de cadena (matriz) de un solo caraacutecter con un

caraacutecter char constante ( 323d) o variable ( 221a) La cadena de un solo caraacutecter es necesariamente la cadena nula su uacutenico elemento es el de fin de cadena Ejemplo

char x1= a L1 variable x1 tipo char valor == ASCII a == 97 decimalconst char x2= a L2 constante x2 tipo const charchar x3 = a L3 variable x3 tipo puntero-a-char sentildeala a cadena de dos caracteres 97 y 0 decimalconst char x4 = a L4 variable x4 tipo puntero a constante caraacutecterchar x5[1]= a L5 variable x5 tipo matriz de un caraacutecter valor x[0]== a == 97 decimal

Los objetos representados por los Rvalues ( 215) de las expresiones anteriores son de distinto tipo y se almacenan con tamantildeos distintos La primera segunda y quinta son constantes caraacutecter (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 tambieacuten muy importante sentildealar que la asignacioacuten

str = AEIOU

solo es posible si str se ha declarado previamente como puntero a caraacutecter es decir

char str sectg

Aunque se puede declarar y definir en la misma sentencia (preferible)

char str = AEIOU secth

El lector observador advertiraacute en la expresioacuten anterior una evidente inconsistencia en la gramaacutetica del C++ En efecto como se ha sentildealado las cadenas literales son de caracteres constantes En

consecuencia no asignables a punteros tales como los definidos en sectg o secth teacutecnicamente punteros a caraacutecter Teoacutericamente solo hubiese sido aceptable la asignacioacuten a puntero-a-caraacutecter-constante tal como

const char str = AEIOU secti

ya que un puntero-a-constante-tipoX no es intercambiable por un puntero-a-tipoX ( 421a) La razoacuten de esta inconsistencia en la definicioacuten de las cadenas literales hay que buscarla en otra de las desafortunadas herencias del C claacutesico y en la necesidad de mantener compatibilidad con millones de liacuteneas de coacutedigo existente En C y en las primitivas versiones de C++ las cadenas literales eran consideradas como de tipo char (puntero a caraacutecter)

Aunque la mayoriacutea de compiladores C++ permiten este tipo de sentencias por razones de tipo histoacuterico parece que tal permisividad tiende a ser deprecated (a extinguir) de forma que las uacuteltimas revisiones de algunos compiladores pueden lanzar una advertencia o error en tales circunstancias La forma canoacutenica de definir este tipo de cadenas seriacutea

const char str[] = AEIOU

La expresioacuten secth define una matriz de seis caracteres constantes (almacenado en alguacuten sitio) que no tiene identificador simple (nombre) Tambieacuten define un puntero str al primer elemento de la matriz (maacutes formalmente es un puntero a caraacutecter) Por tanto a falta de un nombre la matriz tiene que ser accedida a traveacutes del puntero (que tendraacute que ser tratado como tal -puntero-) Sin embargo las expresiones

char arr[] = AEIOU sectjchar arr[6] = AEIOUchar arr[6] = AEIOU0char arr[6] = AEIOUchar arr[6] = AEIOU0

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 (secth ) str es un puntero un objeto que puede ser usado con el aacutelgebra de punteros Por ejemplo es vaacutelida la expresioacuten str++ que

equivale a str = str+1 En los otros cinco casos (sectj ) arr es un nemoacutenico que representa una matriz y la expresioacuten arr++ que equivale a arr = arr+1 es ilegal El operando arr+1 es tratado como (amparr[0])+1 lo que es correcto (a un puntero se le puede sumar un entero) La asignacioacuten no seriacutea correcta porque intentariacutea asignar el puntero amparr[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 asignacioacuten 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 asignacioacuten del tipo x = aeiou Si tiene en cambio poderosas funciones en su Libreriacutea Estaacutendar para hacer todo tipo de manipulaciones con cadenas alfanumeacutericas

Es tambieacuten importante distinguir otra diferencia entre las expresiones

char a1[6] = AEIOU0 p1 = ampa1[0]char a2 = AEIOU

Ambas producen matrices de caracteres absolutamente ideacutenticos en contenido y tamantildeo pero a1 es una matriz por lo que sus elementos podriacutean ser alterados usando el identificador Por ejemplo es vaacutelido a1[1]= e o su equivalente (p1+1)=e En cambio un intento anaacutelogo sobre el segundo obliga a usar necesariamente la versioacuten con puntero (a2+1)=e Ademaacutes de que por las razones ya expuestas [2] el resultado no estaacute 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 todaviacutea la asignacioacuten

a2 = aeiou

En este caso el compilador almacena en alguacuten sitio la cadena aeiou0 y asigna a a2 la direccioacuten 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 ninguacuten modo aunque sigue malgastando espacio de memoria

Tambieacuten es posible declarar cadenas de caracteres anchos con el prefijo L como en el ejemplo

wchar_t wptr = Laeiou

en este caso wptr sentildeala una cadena de caracteres anchos ( 221a1) la cadena es del tipo const wchar_t

Para saber la longitud de una constante literal es necesario que el programa repase la cadena hasta encontrar el caraacutecter de fin de cadena lo que se consigue con la funcioacuten de libreriacutea strlen (incluida en la cabecera estaacutendar ltstringhgt) que proporciona la longitud sin contar el caraacutecter final

sect6 Concatenacioacuten de cadenas

Las cadenas literales adyacentes separadas solo por un especio son automaacuteticamente

concatenadas durante la fase de preprocesado ( 141) de la compilacioacuten Por ejemplo Hola mundo es equivalente a Hola mundo Tambieacuten puede usarse la barra invertida ( ) como siacutembolo de continuacioacuten para extender una cadena literal maacutes allaacute del liacutemite de una liacutenea

puts(En realidad esto es una cadena de una linea)char p = Esto es en otra cadena tambieacuten de una sola liacutenea

La concatenacioacuten suprime el caraacutecter nulo de final en las cadenas intermedias y mantiene el de la uacuteltima Esta operacioacuten no altera el significado de los caracteres que intervienen en las cadenas concatenadas Por ejemplo la concatenacioacuten

xA B

Produce la cadena

xAB

que tiene tres caracteres el hexadecimal xA el caraacutecter B y el caracter final nulo 0 En vez del caraacutecter hexadecimal xAB

La concatenacioacuten de cadenas anchas y estrechas tiene resultados impredecibles

323g Constantes de enumeracioacuten

sect1 Sinopsis

Existe un tipo especial de variables denominadas variables enumeradas o

simplemente enumeraciones ( 48 ) Se caracterizan por poder adoptar valores entre una seleccioacuten de constantes enteras denominadas enumeradores cuyos valores son establecidos en el momento de la declaracioacuten del nuevo tipo Como se ha sentildealado son enteros y (una vez establecidos) de valor constante razoacuten por la que se los denomina tambieacuten constantes de enumeracioacuten

Ejemplo

enum estado MALO =0 REGULAR =1 BUENO =2 EXTRA =3

La sentencia anterior declara estado como un tipo de variable de enumeracioacuten Los miembros de esta clase pueden adoptar los valores indicados y son representados por los nemoacutenicos MALO REGULAR BUENO y EXTRA Estas cuatro constantes son los enumeradores del nuevo tipo

Como advertencia a lo indicado hasta aquiacute no confundir la enumeracioacuten (la variable) con los enumeradores (las constantes enteras que delimitan el conjunto de valores posibles de la variable) Tambieacuten 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 = EXTRAestado tu_estado = REGULAR stdcout ltlt Mi estado actual es ltlt mi_estado ltlt endl -gt Mi estado actual es 3

En el caso anterior estado es una enumeracioacuten (tipo geneacuterico) 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 (geneacuterico) con un tipo enum concreto una instancia (variable enumerada) de ese tipo ni con los valores concretos (constantes de enumeracioacuten) que puede adoptar

Para facilitar la legibilidad los identificadores de las constantes de enumeracioacuten son nemoacutenicos y sus nombres suelen estar en mayuacutesculas debido a una larga tradicioacuten CC++ de representar de este modo las constantes

Ya hemos sentildealado que estas constantes (enumeradores) son de tipo entero por lo que pueden ser utilizadas en cualquier expresioacuten donde sean permitidas las constantes enteras Sus identificadores deben ser uacutenicos dentro del aacutembito de la declaracioacuten enum Se permiten inicializadores negativos los valores que adoptan los enumeradores suelen ser uacutenicos (aunque se permiten duplicidades) Para una visioacuten maacutes detallada de las declaraciones de estas constantes

ver enumeraciones ( 48 ) y la explicacioacuten que sigue sobre la palabra clave enum

sect2 Sintaxis

enum [ltnombre-de-tipogt] ltnombr-constgt [= ltvalorgt] [lista_var]

Puede omitirse la palabra clave enum siempre que el nemoacutenico ltnombre-de-tipogt no sea empleado para nada maacutes en el mismo aacutembito Ejemplo

calidad BUENA REGULAR MALA

En este caso el compilador presupone que calidad es un enumerador y no debe existir otra

definicioacuten en el mismo aacutembito de nombres En otras palabras calidad no debe utilizarse en el mismo aacutembito para designar otro objeto

ltnombre-de-tipogt es una etiqueta opcional que identifica al conjunto Puede omitirse si no se va a usar ninguna otra variable de este tipo de enumeracioacuten Ejemplo

enum CIERTO DUDOSO FALSO

ltnombr-constgt es el nombre de la constante de enumeracioacuten (enumerador) a la que opcionalmente puede asignarse el valor definido porltvalorgt En el ejemplo anterior son tres CIERTO DUDOSO y FALSO

ltvalorgt debe ser un entero (ya se ha sentildealado que los enumeradores son constantes

enteras) Si no se especifica ninguacuten valor se supone que es ltpreviogt + 1 donde ltpreviogt es el valor del enumerador anterior de la lista (el valor por defecto para el primero es cero) ltvalorgtpuede ser cualquier expresioacuten que resulte en un entero positivo o negativo (despueacutes de posible conversioacuten a entero)

ltlista_vargt 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 enumeracioacuten de nombre geneacuterico calidad las variables de este tipo pueden adoptar tres valores 0 1 y 2 identificados respectivamente por los nemoacutenicos BUENO REGULAR y MALO ademaacutes se definen dos variables del nuevo

tipo nota yestado

enum calidad BUENO REGULAR MALO nota estado

sect3 Descripcioacuten

La palabra clave enum define una enumeracioacuten 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 nemoacutenicos Por ejemplo la declaracioacuten

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 nemoacutenicos DOM LUNSAB Ademaacutes 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 nemoacutenicos ULT BW40 C40 BW80 C80 y MONO

Los valores asignados a los enumeradores dependen del formato de la declaracioacuten 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 Ademaacutes como puede comprobarse las expresiones de inicializacioacuten pueden incluir enumeradores previamente declarados

Los valores de los enumeradores no tienen porqueacute ser uacutenicos como en el ejemplo que sigue

enum estado BUENO MALO = 1 REGULAR = 1

326 Puntuadores

sect1 Sinopsis

Los signos de puntuacioacuten del lenguaje C++ juegan el mismo papel que sus homoacutenimos en el lenguaje natural escrito Conocidos tambieacuten comopuntuadores [1] son los que se citan a continuacioacuten La mayoriacutea de ellos tienen un doble uso y en ocasiones funcionan tambieacuten

comooperadores ( 49)

[ ] ( ) = ^ amp ndash + | ~ lt gt

sect2 Corchetes [ ]

Los corchetes indican subiacutendices de matrices uni y multi dimensionales

char ch str[] = Cadena de caracteresint mat[3][4] Matriz de 3 x 4ch = str[3] cuarto elemento

sect3 Pareacutentesis ( )

Los pareacutentesis sirven para agrupar expresiones alterar la precedencia normal de los operadores y su asociatividad aislar expresiones condicionales indicar llamadas a funciones y sentildealar los paraacutemetros de estas La sintaxis de C++ exige indefectiblemente el uso de pareacutentesis en muacuteltiples ocasiones En los ejemplos que siguen se muestran algunos usos

d = c (a + b) modifica la precedencia normalif (d == z) ++x imprescindible en la sentencia iffor (x =1 xlt10 x++) imprescindible en la sentencia forfunc() sentildeala llamada a funcioacutenint func() declara funcioacutenint (fptr)() declara puntero a funcioacutenfptr = func asigna valor al puntero

Observe que en el uacuteltimo caso la ausencia de pareacutentesis equivale a ampfunc ( 424a )

Se recomienda el uso de pareacutentesis en las macro-definiciones para evitar problemas potenciales en la expansioacuten Por ejemplo

define CUBO(x) ((x) (x) (x))

sect4 Llaves

Los pares de llaves sentildealan el comienzo y final de una sentencia compuesta es decir bloques de coacutedigo (grupos de sentencias que son tratadas como una unidad) Constituyen el segundo paso (despueacutes de las sentencias) en la estructuracioacuten y compartimentacioacuten del coacutedigo C++

if (d == z) ++x func()

Un bloque es una sentencia compuesta se trata de una sucesioacuten (que puede estar vaciacutea) de sentencias delimitadas por un par de corchetes Desde el punto de vista sintaacutectico un bloque puede ser considerado como una sola sentencia Juega un papel importante en el aacutembito (scope) de los identificadores puesto que un identificador declarado dentro de un bloque tiene un aacutembito

que comienza en el punto de la declaracioacuten 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)

Despueacutes del corchete de cierre no se necesita el punto y coma de fin de sentencia

if (statement) punto y coma ilegal else

Nota las llaves sirven tambieacuten en C++ para otros usos distintos de la pura delimitacioacuten de bloques de coacutedigo Por ejemplo en la definicioacuten de estructuras uniones y clases en cuyo caso si puede ser necesaria la inclusioacuten del punto y coma despueacutes de la llave de cierre

sect5 Coma

La coma como puntuador se utiliza para separar los elementos en las listas de paraacutemetros de una funcioacuten

void func(int n float f char ch)

La coma se usa tambieacuten como un operador en las expresiones con coma ( 4105) Es posible mezclar los dos usos (separador en lista de paraacutemetros y operador) pero deben usarse pareacutentesis para distinguirlos

sect6 Punto y coma

El punto y coma es el signo de fin de sentencia Cualquier expresioacuten legal C++ terminada por un punto y coma (incluyendo la expresioacuten vaciacutea - un punto y coma aislado-) es interpretado como una

sentencia conocidas como sentencia-expresioacuten ( 410) La expresioacuten se evaluacutea y el resultado se descarta si no tiene efectos colaterales C++ la ignora

a + b evaluacutea a + b descarta el resultado++a efecto lateral en a se descarta el valor ++a expresioacuten vaciacutea = sentencia nula

El punto y coma se usa a veces para crear sentencias nulas

for (i = 0 i lt n i++) sentencia nula (hacer nada)

sect7 Dos puntos

Los dos puntos se utilizan para sentildealar sentencias etiquetadas ( 4101)

comienzo x=0 comienzo es la etiquetagoto comienzo

sect8 Puntos suspensivos

Los puntos suspensivos tambieacuten 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 nuacutemero variable de argumentos o pueden ser de tipo variable ( 441) Por ejemplo

void func(int n char ch)

Este prototipo de funcioacuten declara que func estaacute definida de modo que debe ser llamada con al

menos dos argumentos un int y un char Ademaacutes puede tener un cierto nuacutemero de argumentos adicionales (puede omitirse la coma antes de la elipsis)

Se utiliza tambieacuten para indicar que un manejador de excepciones (handler) puede capturar una

excepcioacuten de cualquier tipo ( 162) Ejemplo

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

Nota como podeacuteis ver en ocasiones mi uso particular en los ejemplos de los tres puntos es para indicar cualquier nuacutemero de sentencias Espero que no sea motivo de confusioacuten Desde luego en el caso anterior seriacutea maacutes correcta la notacioacuten

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

sect9 Asterisco

El asterisco puede ser utilizado en C++ de tres formas como una declaracioacuten de tipo de variable

(variable de puntero 42 ) como operador de indireccioacuten (tambieacuten llamado operador

de dereferencia 4911a) y como operador de multiplicacioacuten

Ejemplos

char char_ptr declara puntero a caraacutecterx = int_ptr operador de indireccioacutenl = 2 314 r operador multiplicacioacuten

sect10 Signo igual =

El signo igual = separa la declaracioacuten de variables de las listas de inicializacioacuten

char array[5] = 1 2 3 4 5

Recordemos que al contrario que en C donde las declaraciones no pueden estar precedidas por ninguacuten coacutedigo deben ir al principio en C++ las declaraciones de cualquier tipo pueden aparecer en cualquier punto del coacutedigo (con algunas restricciones)

En la lista de argumentos de una funcioacuten el signo igual indica el valor por defecto para un paraacutemetro

int f(int i = 0) el valor por defecto de k es cero

El signo igual es tambieacuten utilizado como operador de asignacioacuten ( 492) Ejemplo

x = yz += 5

sect11 Almohadilla

Si la almohadilla aparecen en el primer caraacutecter (distinto de espacio en blanco) de una liacutenea

sentildeala directivas de preproceso ( 4910) En este caso es un operador especiacutefico de la fase

de preproceso del coacutedigo fuente Significa una opcioacuten del preprocesador ( 14) que no tiene porqueacute estar asociada necesariamente a generacioacuten de coacutedigo Las directivas se situacutean generalmente al comienzo del programa aunque legalmente pueden aparecer en cualquier punto

Ejemplos de directivas de preproceso

(null directive)define NULO 0include ltstdiohgt

4 Estructura del lenguaje

sect1 Sinopsis

Esta parte proporciona una definicioacuten formal del lenguaje C++ describiendo las formas en que

pueden agruparse correctamente los tokens ( 32) palabras que constituyen el lenguaje entendible por el compilador para formar declaraciones expresiones y otras unidades significativas Para su anaacutelisis lo hemos descompuesto en 13 grupos seguacuten la clasificacioacuten que sigue

sect41 Declaraciones

ObjetosReferencias amp definicionesDefinicioacuten provisionalAacutembitoVisibilidadDuracioacutenUnidad de compilacioacutenEnlazado

Sintaxis de declaraciones

Conversiones aritmeacuteticasInicializacioacutenEspecificadores de clase de almacenamientoModificadores auxiliaresModificadores de funcioacuten

sect42 Punteros

Puntero a objetoDeclaracioacuten de punterosAritmeacutetica de punterosReferenciasPuntero a funcioacuten

sect43 Matrices

Declaracioacuten de matricesMatrices alfanumeacutericasMatrices de punterosMatrices de matrices

sect44 Funciones

DeclaracioacutenDefinicioacutenArgumentos formales y actualesLlamada y conversioacuten de argumentosValores devueltos

sect45 Estructuras

Declaracioacuten de estructurasInicializacioacutenOperaciones permitidasAcceso a miembrosEstructuras y funcionesMatrices de estructurasPunteros a estructurasEstructuras auto-referenciadas

sect46 Campos de Bits

sect47 Uniones

sect48 Enumeraciones

Expresiones

Asociatividad y precedencia de operadoresOrden de evaluacioacutenErrores y desbordamientosExpresiones con coma

sect49 Operadores

AritmeacuteticosAsignacioacutenManejo de BitsOperador ComaCondicionalOp de igualdadOp LoacutegicosModelado de tiposOp de PreprocesoOp de punteroRelacionalessizeoftypeidOp primariosOp antildeadidosOp UnitariosSobrecarga de OperadoresOperador Operador newOperador delete

sect410 Sentencias

Sentencias de etiqueta case defaultSentencias de seleccioacuten if hellip else else if switchSentencias de iteracioacuten while dowhile forSentencias de salto break continue goto return

sect411 Clases

CreacioacutenDeclaracioacutenNombres de ClasesAacutembito de nombresInstanciado de Clasesthis (palabra reservada)Miembros estaacuteticosClases polimoacuterficasFunciones virtualesFunciones dinaacutemicasClases abstractas

sect412 Plantillas

Funciones geneacutericasClases geneacutericas

Aunque las secciones anteriores describen completamente el lenguaje desde una perspectiva formal hemos antildeadido un capiacutetulo adicional (sect413) dedicado a los tecnicismos En eacutel se incluyen algunos consejos y reglas de buena praacutectica para la programacioacuten C++ asiacute como algunos idioms

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

41 Declaraciones

sect1 Sinopsis

Una declaracioacuten es una claacuteusula que introduce nombres en una unidad de compilacioacuten ( 142) o redeclara nombres introducidos por declaraciones previas La norma sentildeala que una declaracioacuten especifica la interpretacioacuten y atributos de estos nombres (como tipo de enlazado y de almacenamiento si es un objeto) asiacute como las condiciones para que una declaracioacuten no sea

tambieacuten una definicioacuten En la paacutegina adjunta se muestra su gramaacutetica ( Gramaacutetica)

Cada una de las introducciones unitarias que puede existir en una declaracioacuten es un declarador (declarator) Asiacute pues un declarador introduce un nombre o redeclara uno

declarado previamente La paacutegina adjunta muestra su gramaacutetica ( Gramaacutetica)

El presente capiacutetulo repasa este importante concepto y otros relacionados tales como objetos clases de almacenamiento tipos aacutembitovisibilidad duracioacuten y enlazado

El aacutembito visibilidad duracioacuten y enlazado son propiedades o caracteriacutesticas 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 definicioacuten de declaracioacuten o la exposicioacuten de su sintaxis

En el epiacutegrafe 4111 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 tambieacuten es dada a conocer mediante una declaracioacuten

411 Entidades

sect1 Presentacioacuten

En relacioacuten con los conceptos que aquiacute nos incumben consideramos que una entidad ( 121) 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 objeto-valor

Un algoritmo con informacioacuten sobre manipulacioacuten de datos Lo denominamos entidad-algoritmo o simplemente algoritmo

Respecto a los objetos-valor una posible clasificacioacuten podriacutea dividirlos en las siguientes categoriacuteas

Agregados

o matrizo estructurao unioacuteno clase unioacuten

Funciones Escalares

o Aritmeacuteticoo Enumeracioacuteno Booleanoo Punteroo Referencia

void

void ( 221) es un tipo especial con un valor muy particular ausencia de valor Los escalares son de caracteriacutesticas tales que su valor no pueden ser descompuestos en partes maacutes pequentildeas

por ejemplo un entero un valor loacutegico (cierto-falso) etc Las funciones ( 44) son principalmente algoritmo ya que estaacuten asociadas a ciertas operaciones (cierta computacioacuten) pero por convencioacuten se les puede asignar un valor es el que devuelven (puede ser void) Por su parte los agregados comparten la caracteriacutestica de que su valor puede ser descompuesto en elementos maacutes simples (escalares)

sect2 El papel de las declaraciones

Haciendo un siacutemil social podriacuteamos decir que las declaraciones son las encargadas de presentar al compilador cualquier entidad que deba existir en el programa Son por tanto el Chambelaacuten de la sociedad C++ Como en el caso de las presentaciones sociales esta presentacioacuten no se reduce a indicar el nombre tambieacuten puede sentildealarse algunas caracteriacutesticas 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

sect3 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 expresioacuten compleja que

represente uniacutevocamente al objeto ( 211 ) Cualquier intento de utilizar una declaracioacuten sin un nombre es un error aunque el nombre no tiene que responder necesariamente a un objeto o funcioacuten Ejemplo

extern int Errorchar Errorchar cptr Ok cptr nombre de punteroclass C Ok C nombre de clasetypedef unsigned int UINT Ok UINT alias para un tipo conocido

Ademaacutes del identificador las declaraciones de funciones pueden incluir ciertos atributos inline ( 4112a) virtual ( 4118a) y explicit ( 4112d1)

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 ( 21 ) Entre otros puede incluir los siguientes char wchar_t bool short int long signed unsigned float double void

Relativos al tipo de almacenamiento Determina el sitio en que se guarda el objeto y su

duracioacuten ( 213 ) 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 disquisicioacuten respecto a si un mismo objeto Por ejemplo una variable puede estar referenciado por dos identificadores distintos (que se refieren a la misma regioacuten de memoria) En la mayoriacutea de lenguajes de programacioacuten esta distincioacuten entre identificador y almacenamiento estaacute perfectamente establecida y suelen proporcionar mecanismos sintaacutecticos para que dos identificadores puedan referirse al mismo almacenamiento

412 Declaraciones y definiciones

sect1 Sinopsis

Utilizando un leacutexico formalista podemos decir que una declaracioacuten es una sentencia que

introduce un nombre en una unidad de compilacioacuten ( 142) daacutendole existencia semaacutentica Esto de la existencia semaacutentica es una forma elegante de decir que a partir de ahiacute el compilador sabe que cosa es (representa) ese nombre La forma de darle existencia semaacutentica a las entidades es declararlos (algo asiacute como presentarlos formalmente en el coacutedigo) Por ejemplo si declaramos una variable x o una funcioacuten func a partir de ahiacute el compilador sabe que x es una variable de tal tipo y que func es una funcioacuten de caracteriacutesticas cuales

El punto importante a resaltar aquiacute es que cada declaracioacuten asocia un nombre con un tipo de dato

lo que en C++ (una sociedad muy clasista 22) es importante ya que el conocimiento del tipo que corresponde a un identificador proporciona al compilador mucha informacioacuten sobre la entidad

representada por este (en muchas ocasiones casi toda la informacioacuten necesaria ) En especial el compilador dispone de una amplia informacioacuten acerca del uso de los tipos baacutesicos que operaciones son permitidas y que significado tienen estas operaciones

No olvidar que una declaracioacuten no hace nada maacutes que esto Es decir no antildeade ninguna otra informacioacuten distinta de relacionar una etiqueta con un tipo Posteriormente cuando esta etiqueta esteacute asociada con una entidad concreta (con una zona de memoria) las operaciones permitidas se

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

El texto de una cadena literal puede contener cualquier caraacutecter del juego de caracteres

imprimibles ASCII ( 221a) Para representar los caracteres no imprimibles se utilizan las

denominadas secuencias de escape un truco que consiste en sustituir cada caraacutecter no imprimible por una secuencia de dos o tres caracteres Naturalmente una cadena literal no debe contener un caraacutecter nulo en su interior (que como hemos indicado sentildeala el final de la cadena) en caso contrario al aplicarse las funciones de Libreriacutea Estaacutendar claacutesicas (heredadas de C) el resultado es impredecible

sect11 El punto importante a entender aquiacute podriacutea sintetizarse en que desde la oacuteptica 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 atencioacuten a que el antiguo coacutedigo C sea compatible con los

compiladores C++

Si la cadena no estaacute precedida por la letra L es una matriz de caracteres tipo const char (

323) tambieacuten denominada cadena estrecha u ordinaria (Narrow string literal)

Si la cadena estaacute precedida por la letra L los miembros de la matriz son caracteres anchos

( 221a1) del tipo const w_char y se denomina cadena ancha (Wide string literal)

Estos objetos tienen almacenamiento estaacutetico en el sentido indicado en 226 es decir que el compilador conoce los valores en tiempo de compilacioacuten y que probablemente sean

guardados en el segmento ( 132) [4]

sect12 Generalmente aparecen a la derecha en expresiones de asignacioacuten o como paraacutemetros de funciones pueden aparecer incluso como valores devueltos por funciones Ejemplos

char ptr = Hola mundoprintf(sn Soy una cadena literal)cout ltlt acabo de llegar ltlt endlreturn Se termina la funcioacuten

sect2 Secuencias de escape

Dentro de las comillas se pueden representar caracteres especiales (no imprimibles)

mediante secuencias de escape ( 323e) Por ejemplo el coacutedigo

ttNombretDireccioacutennn

Se representa como

Nombre Direccioacuten

Nombre es precedido por dos tabulaciones Direccioacuten esta precedido por una tabulacioacuten La liacutenea va seguida de dos nueva liacutenea (NL) La secuencia proporciona las comillas interiores Si se

compila con la opcioacuten -A para compatibilidad ANSI la secuencia de escape es traducida por el compilador a

sect3 Como hemos sentildealado en C++ las cadenas alfanumeacutericas son teacutecnicamente matrices de caracteres constantes se almacenan internamente como secuencias de caracteres maacutes un caraacutecter final nulo 0 lo que significa que el almacenamiento usado es igual a la longitud visible de la cadena mas uno Seguacuten esto la cadena nula es almacenada como un solo caraacutecter 0 y no hay maacutes liacutemite que la memoria disponible para la longitud posible de una cadena Por ejemplo la cadena Holan se guarda internamente como

H o l a n 0

Nota histoacuterica El meacutetodo de identificar el final de cadena mediante un caraacutecter nulo es ineficiente y aparte de que no permite utilizar cadenas que contengan un caraacutecter nulo en su interior (por ejemplo ficheros binarios) su manejo conlleva problemas de rendimiento [3]

Aparentemente la razoacuten por la que C y C++ utilizan este meacutetodo se debe a que C se desarrolloacute

sobre maacutequinas Unix ( 1 ) y a su vez este sistema operativo fue desarrollado inicialmente sobre una maacutequina DEC (Digital Equipment Corporation) PDP-7 que teniacutean un tipo de dato denominado ASICZ (ASCII con un Zero al final) que era directamente reconocible por su ensamblador

sect4 Peculiaridades

En el preaacutembulo sentildealamos 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 ninguacuten 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 uacutenica singularidad es que el compilador C++ les permite ciertas formas particulares de definicioacuten y declaracioacuten que les confiere cierta personalidad

Por ejemplo el hecho de inicializarlas directamente con expresiones como las sentildealadas sect12 o que antildeada automaacuteticamente el caraacutecter nulo de terminacioacuten a los caracteres expliacutecitamente indicados por el programador

Respecto a esto uacuteltimo solo tiene justificacioacuten histoacuterica porque el caraacutecter nulo se utilizaba en las antiguas funciones de libreriacutea para indicar el final de la cadena Por esta razoacuten aunque es posible incluir caracteres nulos dentro de las cadenas literales Por ejemplo Hola0 mundo no estaacute garantizado que funcione en todos los casos (seraacute malinterpretado por las funciones printf strcpy y strlen de la Libreriacutea Estaacutendar)

Ejemplo

char ptr = Hola0 mundoprintf(sn ptr)

Salida

Hola

sect5 Una cadena nula (vaciacutea) se representa o 0 tiene un solo caraacutecter el caraacutecter nulo (ver a continuacioacuten) Observe que desde el punto de vista del Rvalue la constante de cadena A es A

0 mientras que la constante caraacutecter ( 323d) A es A

Se considera que la longitud de un NTBS es el nuacutemero de caracteres que preceden al de terminacioacuten de forma que la cadena nula tiene longitud 0 (aunque en realidad contiene un caraacutecter) Sin embargo el valor de la cadena incluye el caraacutecter de final

Conviene no confundir una constante de cadena (matriz) de un solo caraacutecter con un

caraacutecter char constante ( 323d) o variable ( 221a) La cadena de un solo caraacutecter es necesariamente la cadena nula su uacutenico elemento es el de fin de cadena Ejemplo

char x1= a L1 variable x1 tipo char valor == ASCII a == 97 decimalconst char x2= a L2 constante x2 tipo const charchar x3 = a L3 variable x3 tipo puntero-a-char sentildeala a cadena de dos caracteres 97 y 0 decimalconst char x4 = a L4 variable x4 tipo puntero a constante caraacutecterchar x5[1]= a L5 variable x5 tipo matriz de un caraacutecter valor x[0]== a == 97 decimal

Los objetos representados por los Rvalues ( 215) de las expresiones anteriores son de distinto tipo y se almacenan con tamantildeos distintos La primera segunda y quinta son constantes caraacutecter (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 tambieacuten muy importante sentildealar que la asignacioacuten

str = AEIOU

solo es posible si str se ha declarado previamente como puntero a caraacutecter es decir

char str sectg

Aunque se puede declarar y definir en la misma sentencia (preferible)

char str = AEIOU secth

El lector observador advertiraacute en la expresioacuten anterior una evidente inconsistencia en la gramaacutetica del C++ En efecto como se ha sentildealado las cadenas literales son de caracteres constantes En

consecuencia no asignables a punteros tales como los definidos en sectg o secth teacutecnicamente punteros a caraacutecter Teoacutericamente solo hubiese sido aceptable la asignacioacuten a puntero-a-caraacutecter-constante tal como

const char str = AEIOU secti

ya que un puntero-a-constante-tipoX no es intercambiable por un puntero-a-tipoX ( 421a) La razoacuten de esta inconsistencia en la definicioacuten de las cadenas literales hay que buscarla en otra de las desafortunadas herencias del C claacutesico y en la necesidad de mantener compatibilidad con millones de liacuteneas de coacutedigo existente En C y en las primitivas versiones de C++ las cadenas literales eran consideradas como de tipo char (puntero a caraacutecter)

Aunque la mayoriacutea de compiladores C++ permiten este tipo de sentencias por razones de tipo histoacuterico parece que tal permisividad tiende a ser deprecated (a extinguir) de forma que las uacuteltimas revisiones de algunos compiladores pueden lanzar una advertencia o error en tales circunstancias La forma canoacutenica de definir este tipo de cadenas seriacutea

const char str[] = AEIOU

La expresioacuten secth define una matriz de seis caracteres constantes (almacenado en alguacuten sitio) que no tiene identificador simple (nombre) Tambieacuten define un puntero str al primer elemento de la matriz (maacutes formalmente es un puntero a caraacutecter) Por tanto a falta de un nombre la matriz tiene que ser accedida a traveacutes del puntero (que tendraacute que ser tratado como tal -puntero-) Sin embargo las expresiones

char arr[] = AEIOU sectjchar arr[6] = AEIOUchar arr[6] = AEIOU0char arr[6] = AEIOUchar arr[6] = AEIOU0

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 (secth ) str es un puntero un objeto que puede ser usado con el aacutelgebra de punteros Por ejemplo es vaacutelida la expresioacuten str++ que

equivale a str = str+1 En los otros cinco casos (sectj ) arr es un nemoacutenico que representa una matriz y la expresioacuten arr++ que equivale a arr = arr+1 es ilegal El operando arr+1 es tratado como (amparr[0])+1 lo que es correcto (a un puntero se le puede sumar un entero) La asignacioacuten no seriacutea correcta porque intentariacutea asignar el puntero amparr[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 asignacioacuten 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 asignacioacuten del tipo x = aeiou Si tiene en cambio poderosas funciones en su Libreriacutea Estaacutendar para hacer todo tipo de manipulaciones con cadenas alfanumeacutericas

Es tambieacuten importante distinguir otra diferencia entre las expresiones

char a1[6] = AEIOU0 p1 = ampa1[0]char a2 = AEIOU

Ambas producen matrices de caracteres absolutamente ideacutenticos en contenido y tamantildeo pero a1 es una matriz por lo que sus elementos podriacutean ser alterados usando el identificador Por ejemplo es vaacutelido a1[1]= e o su equivalente (p1+1)=e En cambio un intento anaacutelogo sobre el segundo obliga a usar necesariamente la versioacuten con puntero (a2+1)=e Ademaacutes de que por las razones ya expuestas [2] el resultado no estaacute 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 todaviacutea la asignacioacuten

a2 = aeiou

En este caso el compilador almacena en alguacuten sitio la cadena aeiou0 y asigna a a2 la direccioacuten 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 ninguacuten modo aunque sigue malgastando espacio de memoria

Tambieacuten es posible declarar cadenas de caracteres anchos con el prefijo L como en el ejemplo

wchar_t wptr = Laeiou

en este caso wptr sentildeala una cadena de caracteres anchos ( 221a1) la cadena es del tipo const wchar_t

Para saber la longitud de una constante literal es necesario que el programa repase la cadena hasta encontrar el caraacutecter de fin de cadena lo que se consigue con la funcioacuten de libreriacutea strlen (incluida en la cabecera estaacutendar ltstringhgt) que proporciona la longitud sin contar el caraacutecter final

sect6 Concatenacioacuten de cadenas

Las cadenas literales adyacentes separadas solo por un especio son automaacuteticamente

concatenadas durante la fase de preprocesado ( 141) de la compilacioacuten Por ejemplo Hola mundo es equivalente a Hola mundo Tambieacuten puede usarse la barra invertida ( ) como siacutembolo de continuacioacuten para extender una cadena literal maacutes allaacute del liacutemite de una liacutenea

puts(En realidad esto es una cadena de una linea)char p = Esto es en otra cadena tambieacuten de una sola liacutenea

La concatenacioacuten suprime el caraacutecter nulo de final en las cadenas intermedias y mantiene el de la uacuteltima Esta operacioacuten no altera el significado de los caracteres que intervienen en las cadenas concatenadas Por ejemplo la concatenacioacuten

xA B

Produce la cadena

xAB

que tiene tres caracteres el hexadecimal xA el caraacutecter B y el caracter final nulo 0 En vez del caraacutecter hexadecimal xAB

La concatenacioacuten de cadenas anchas y estrechas tiene resultados impredecibles

323g Constantes de enumeracioacuten

sect1 Sinopsis

Existe un tipo especial de variables denominadas variables enumeradas o

simplemente enumeraciones ( 48 ) Se caracterizan por poder adoptar valores entre una seleccioacuten de constantes enteras denominadas enumeradores cuyos valores son establecidos en el momento de la declaracioacuten del nuevo tipo Como se ha sentildealado son enteros y (una vez establecidos) de valor constante razoacuten por la que se los denomina tambieacuten constantes de enumeracioacuten

Ejemplo

enum estado MALO =0 REGULAR =1 BUENO =2 EXTRA =3

La sentencia anterior declara estado como un tipo de variable de enumeracioacuten Los miembros de esta clase pueden adoptar los valores indicados y son representados por los nemoacutenicos MALO REGULAR BUENO y EXTRA Estas cuatro constantes son los enumeradores del nuevo tipo

Como advertencia a lo indicado hasta aquiacute no confundir la enumeracioacuten (la variable) con los enumeradores (las constantes enteras que delimitan el conjunto de valores posibles de la variable) Tambieacuten 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 = EXTRAestado tu_estado = REGULAR stdcout ltlt Mi estado actual es ltlt mi_estado ltlt endl -gt Mi estado actual es 3

En el caso anterior estado es una enumeracioacuten (tipo geneacuterico) 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 (geneacuterico) con un tipo enum concreto una instancia (variable enumerada) de ese tipo ni con los valores concretos (constantes de enumeracioacuten) que puede adoptar

Para facilitar la legibilidad los identificadores de las constantes de enumeracioacuten son nemoacutenicos y sus nombres suelen estar en mayuacutesculas debido a una larga tradicioacuten CC++ de representar de este modo las constantes

Ya hemos sentildealado que estas constantes (enumeradores) son de tipo entero por lo que pueden ser utilizadas en cualquier expresioacuten donde sean permitidas las constantes enteras Sus identificadores deben ser uacutenicos dentro del aacutembito de la declaracioacuten enum Se permiten inicializadores negativos los valores que adoptan los enumeradores suelen ser uacutenicos (aunque se permiten duplicidades) Para una visioacuten maacutes detallada de las declaraciones de estas constantes

ver enumeraciones ( 48 ) y la explicacioacuten que sigue sobre la palabra clave enum

sect2 Sintaxis

enum [ltnombre-de-tipogt] ltnombr-constgt [= ltvalorgt] [lista_var]

Puede omitirse la palabra clave enum siempre que el nemoacutenico ltnombre-de-tipogt no sea empleado para nada maacutes en el mismo aacutembito Ejemplo

calidad BUENA REGULAR MALA

En este caso el compilador presupone que calidad es un enumerador y no debe existir otra

definicioacuten en el mismo aacutembito de nombres En otras palabras calidad no debe utilizarse en el mismo aacutembito para designar otro objeto

ltnombre-de-tipogt es una etiqueta opcional que identifica al conjunto Puede omitirse si no se va a usar ninguna otra variable de este tipo de enumeracioacuten Ejemplo

enum CIERTO DUDOSO FALSO

ltnombr-constgt es el nombre de la constante de enumeracioacuten (enumerador) a la que opcionalmente puede asignarse el valor definido porltvalorgt En el ejemplo anterior son tres CIERTO DUDOSO y FALSO

ltvalorgt debe ser un entero (ya se ha sentildealado que los enumeradores son constantes

enteras) Si no se especifica ninguacuten valor se supone que es ltpreviogt + 1 donde ltpreviogt es el valor del enumerador anterior de la lista (el valor por defecto para el primero es cero) ltvalorgtpuede ser cualquier expresioacuten que resulte en un entero positivo o negativo (despueacutes de posible conversioacuten a entero)

ltlista_vargt 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 enumeracioacuten de nombre geneacuterico calidad las variables de este tipo pueden adoptar tres valores 0 1 y 2 identificados respectivamente por los nemoacutenicos BUENO REGULAR y MALO ademaacutes se definen dos variables del nuevo

tipo nota yestado

enum calidad BUENO REGULAR MALO nota estado

sect3 Descripcioacuten

La palabra clave enum define una enumeracioacuten 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 nemoacutenicos Por ejemplo la declaracioacuten

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 nemoacutenicos DOM LUNSAB Ademaacutes 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 nemoacutenicos ULT BW40 C40 BW80 C80 y MONO

Los valores asignados a los enumeradores dependen del formato de la declaracioacuten 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 Ademaacutes como puede comprobarse las expresiones de inicializacioacuten pueden incluir enumeradores previamente declarados

Los valores de los enumeradores no tienen porqueacute ser uacutenicos como en el ejemplo que sigue

enum estado BUENO MALO = 1 REGULAR = 1

326 Puntuadores

sect1 Sinopsis

Los signos de puntuacioacuten del lenguaje C++ juegan el mismo papel que sus homoacutenimos en el lenguaje natural escrito Conocidos tambieacuten comopuntuadores [1] son los que se citan a continuacioacuten La mayoriacutea de ellos tienen un doble uso y en ocasiones funcionan tambieacuten

comooperadores ( 49)

[ ] ( ) = ^ amp ndash + | ~ lt gt

sect2 Corchetes [ ]

Los corchetes indican subiacutendices de matrices uni y multi dimensionales

char ch str[] = Cadena de caracteresint mat[3][4] Matriz de 3 x 4ch = str[3] cuarto elemento

sect3 Pareacutentesis ( )

Los pareacutentesis sirven para agrupar expresiones alterar la precedencia normal de los operadores y su asociatividad aislar expresiones condicionales indicar llamadas a funciones y sentildealar los paraacutemetros de estas La sintaxis de C++ exige indefectiblemente el uso de pareacutentesis en muacuteltiples ocasiones En los ejemplos que siguen se muestran algunos usos

d = c (a + b) modifica la precedencia normalif (d == z) ++x imprescindible en la sentencia iffor (x =1 xlt10 x++) imprescindible en la sentencia forfunc() sentildeala llamada a funcioacutenint func() declara funcioacutenint (fptr)() declara puntero a funcioacutenfptr = func asigna valor al puntero

Observe que en el uacuteltimo caso la ausencia de pareacutentesis equivale a ampfunc ( 424a )

Se recomienda el uso de pareacutentesis en las macro-definiciones para evitar problemas potenciales en la expansioacuten Por ejemplo

define CUBO(x) ((x) (x) (x))

sect4 Llaves

Los pares de llaves sentildealan el comienzo y final de una sentencia compuesta es decir bloques de coacutedigo (grupos de sentencias que son tratadas como una unidad) Constituyen el segundo paso (despueacutes de las sentencias) en la estructuracioacuten y compartimentacioacuten del coacutedigo C++

if (d == z) ++x func()

Un bloque es una sentencia compuesta se trata de una sucesioacuten (que puede estar vaciacutea) de sentencias delimitadas por un par de corchetes Desde el punto de vista sintaacutectico un bloque puede ser considerado como una sola sentencia Juega un papel importante en el aacutembito (scope) de los identificadores puesto que un identificador declarado dentro de un bloque tiene un aacutembito

que comienza en el punto de la declaracioacuten 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)

Despueacutes del corchete de cierre no se necesita el punto y coma de fin de sentencia

if (statement) punto y coma ilegal else

Nota las llaves sirven tambieacuten en C++ para otros usos distintos de la pura delimitacioacuten de bloques de coacutedigo Por ejemplo en la definicioacuten de estructuras uniones y clases en cuyo caso si puede ser necesaria la inclusioacuten del punto y coma despueacutes de la llave de cierre

sect5 Coma

La coma como puntuador se utiliza para separar los elementos en las listas de paraacutemetros de una funcioacuten

void func(int n float f char ch)

La coma se usa tambieacuten como un operador en las expresiones con coma ( 4105) Es posible mezclar los dos usos (separador en lista de paraacutemetros y operador) pero deben usarse pareacutentesis para distinguirlos

sect6 Punto y coma

El punto y coma es el signo de fin de sentencia Cualquier expresioacuten legal C++ terminada por un punto y coma (incluyendo la expresioacuten vaciacutea - un punto y coma aislado-) es interpretado como una

sentencia conocidas como sentencia-expresioacuten ( 410) La expresioacuten se evaluacutea y el resultado se descarta si no tiene efectos colaterales C++ la ignora

a + b evaluacutea a + b descarta el resultado++a efecto lateral en a se descarta el valor ++a expresioacuten vaciacutea = sentencia nula

El punto y coma se usa a veces para crear sentencias nulas

for (i = 0 i lt n i++) sentencia nula (hacer nada)

sect7 Dos puntos

Los dos puntos se utilizan para sentildealar sentencias etiquetadas ( 4101)

comienzo x=0 comienzo es la etiquetagoto comienzo

sect8 Puntos suspensivos

Los puntos suspensivos tambieacuten 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 nuacutemero variable de argumentos o pueden ser de tipo variable ( 441) Por ejemplo

void func(int n char ch)

Este prototipo de funcioacuten declara que func estaacute definida de modo que debe ser llamada con al

menos dos argumentos un int y un char Ademaacutes puede tener un cierto nuacutemero de argumentos adicionales (puede omitirse la coma antes de la elipsis)

Se utiliza tambieacuten para indicar que un manejador de excepciones (handler) puede capturar una

excepcioacuten de cualquier tipo ( 162) Ejemplo

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

Nota como podeacuteis ver en ocasiones mi uso particular en los ejemplos de los tres puntos es para indicar cualquier nuacutemero de sentencias Espero que no sea motivo de confusioacuten Desde luego en el caso anterior seriacutea maacutes correcta la notacioacuten

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

sect9 Asterisco

El asterisco puede ser utilizado en C++ de tres formas como una declaracioacuten de tipo de variable

(variable de puntero 42 ) como operador de indireccioacuten (tambieacuten llamado operador

de dereferencia 4911a) y como operador de multiplicacioacuten

Ejemplos

char char_ptr declara puntero a caraacutecterx = int_ptr operador de indireccioacutenl = 2 314 r operador multiplicacioacuten

sect10 Signo igual =

El signo igual = separa la declaracioacuten de variables de las listas de inicializacioacuten

char array[5] = 1 2 3 4 5

Recordemos que al contrario que en C donde las declaraciones no pueden estar precedidas por ninguacuten coacutedigo deben ir al principio en C++ las declaraciones de cualquier tipo pueden aparecer en cualquier punto del coacutedigo (con algunas restricciones)

En la lista de argumentos de una funcioacuten el signo igual indica el valor por defecto para un paraacutemetro

int f(int i = 0) el valor por defecto de k es cero

El signo igual es tambieacuten utilizado como operador de asignacioacuten ( 492) Ejemplo

x = yz += 5

sect11 Almohadilla

Si la almohadilla aparecen en el primer caraacutecter (distinto de espacio en blanco) de una liacutenea

sentildeala directivas de preproceso ( 4910) En este caso es un operador especiacutefico de la fase

de preproceso del coacutedigo fuente Significa una opcioacuten del preprocesador ( 14) que no tiene porqueacute estar asociada necesariamente a generacioacuten de coacutedigo Las directivas se situacutean generalmente al comienzo del programa aunque legalmente pueden aparecer en cualquier punto

Ejemplos de directivas de preproceso

(null directive)define NULO 0include ltstdiohgt

4 Estructura del lenguaje

sect1 Sinopsis

Esta parte proporciona una definicioacuten formal del lenguaje C++ describiendo las formas en que

pueden agruparse correctamente los tokens ( 32) palabras que constituyen el lenguaje entendible por el compilador para formar declaraciones expresiones y otras unidades significativas Para su anaacutelisis lo hemos descompuesto en 13 grupos seguacuten la clasificacioacuten que sigue

sect41 Declaraciones

ObjetosReferencias amp definicionesDefinicioacuten provisionalAacutembitoVisibilidadDuracioacutenUnidad de compilacioacutenEnlazado

Sintaxis de declaraciones

Conversiones aritmeacuteticasInicializacioacutenEspecificadores de clase de almacenamientoModificadores auxiliaresModificadores de funcioacuten

sect42 Punteros

Puntero a objetoDeclaracioacuten de punterosAritmeacutetica de punterosReferenciasPuntero a funcioacuten

sect43 Matrices

Declaracioacuten de matricesMatrices alfanumeacutericasMatrices de punterosMatrices de matrices

sect44 Funciones

DeclaracioacutenDefinicioacutenArgumentos formales y actualesLlamada y conversioacuten de argumentosValores devueltos

sect45 Estructuras

Declaracioacuten de estructurasInicializacioacutenOperaciones permitidasAcceso a miembrosEstructuras y funcionesMatrices de estructurasPunteros a estructurasEstructuras auto-referenciadas

sect46 Campos de Bits

sect47 Uniones

sect48 Enumeraciones

Expresiones

Asociatividad y precedencia de operadoresOrden de evaluacioacutenErrores y desbordamientosExpresiones con coma

sect49 Operadores

AritmeacuteticosAsignacioacutenManejo de BitsOperador ComaCondicionalOp de igualdadOp LoacutegicosModelado de tiposOp de PreprocesoOp de punteroRelacionalessizeoftypeidOp primariosOp antildeadidosOp UnitariosSobrecarga de OperadoresOperador Operador newOperador delete

sect410 Sentencias

Sentencias de etiqueta case defaultSentencias de seleccioacuten if hellip else else if switchSentencias de iteracioacuten while dowhile forSentencias de salto break continue goto return

sect411 Clases

CreacioacutenDeclaracioacutenNombres de ClasesAacutembito de nombresInstanciado de Clasesthis (palabra reservada)Miembros estaacuteticosClases polimoacuterficasFunciones virtualesFunciones dinaacutemicasClases abstractas

sect412 Plantillas

Funciones geneacutericasClases geneacutericas

Aunque las secciones anteriores describen completamente el lenguaje desde una perspectiva formal hemos antildeadido un capiacutetulo adicional (sect413) dedicado a los tecnicismos En eacutel se incluyen algunos consejos y reglas de buena praacutectica para la programacioacuten C++ asiacute como algunos idioms

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

41 Declaraciones

sect1 Sinopsis

Una declaracioacuten es una claacuteusula que introduce nombres en una unidad de compilacioacuten ( 142) o redeclara nombres introducidos por declaraciones previas La norma sentildeala que una declaracioacuten especifica la interpretacioacuten y atributos de estos nombres (como tipo de enlazado y de almacenamiento si es un objeto) asiacute como las condiciones para que una declaracioacuten no sea

tambieacuten una definicioacuten En la paacutegina adjunta se muestra su gramaacutetica ( Gramaacutetica)

Cada una de las introducciones unitarias que puede existir en una declaracioacuten es un declarador (declarator) Asiacute pues un declarador introduce un nombre o redeclara uno

declarado previamente La paacutegina adjunta muestra su gramaacutetica ( Gramaacutetica)

El presente capiacutetulo repasa este importante concepto y otros relacionados tales como objetos clases de almacenamiento tipos aacutembitovisibilidad duracioacuten y enlazado

El aacutembito visibilidad duracioacuten y enlazado son propiedades o caracteriacutesticas 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 definicioacuten de declaracioacuten o la exposicioacuten de su sintaxis

En el epiacutegrafe 4111 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 tambieacuten es dada a conocer mediante una declaracioacuten

411 Entidades

sect1 Presentacioacuten

En relacioacuten con los conceptos que aquiacute nos incumben consideramos que una entidad ( 121) 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 objeto-valor

Un algoritmo con informacioacuten sobre manipulacioacuten de datos Lo denominamos entidad-algoritmo o simplemente algoritmo

Respecto a los objetos-valor una posible clasificacioacuten podriacutea dividirlos en las siguientes categoriacuteas

Agregados

o matrizo estructurao unioacuteno clase unioacuten

Funciones Escalares

o Aritmeacuteticoo Enumeracioacuteno Booleanoo Punteroo Referencia

void

void ( 221) es un tipo especial con un valor muy particular ausencia de valor Los escalares son de caracteriacutesticas tales que su valor no pueden ser descompuestos en partes maacutes pequentildeas

por ejemplo un entero un valor loacutegico (cierto-falso) etc Las funciones ( 44) son principalmente algoritmo ya que estaacuten asociadas a ciertas operaciones (cierta computacioacuten) pero por convencioacuten se les puede asignar un valor es el que devuelven (puede ser void) Por su parte los agregados comparten la caracteriacutestica de que su valor puede ser descompuesto en elementos maacutes simples (escalares)

sect2 El papel de las declaraciones

Haciendo un siacutemil social podriacuteamos decir que las declaraciones son las encargadas de presentar al compilador cualquier entidad que deba existir en el programa Son por tanto el Chambelaacuten de la sociedad C++ Como en el caso de las presentaciones sociales esta presentacioacuten no se reduce a indicar el nombre tambieacuten puede sentildealarse algunas caracteriacutesticas 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

sect3 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 expresioacuten compleja que

represente uniacutevocamente al objeto ( 211 ) Cualquier intento de utilizar una declaracioacuten sin un nombre es un error aunque el nombre no tiene que responder necesariamente a un objeto o funcioacuten Ejemplo

extern int Errorchar Errorchar cptr Ok cptr nombre de punteroclass C Ok C nombre de clasetypedef unsigned int UINT Ok UINT alias para un tipo conocido

Ademaacutes del identificador las declaraciones de funciones pueden incluir ciertos atributos inline ( 4112a) virtual ( 4118a) y explicit ( 4112d1)

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 ( 21 ) Entre otros puede incluir los siguientes char wchar_t bool short int long signed unsigned float double void

Relativos al tipo de almacenamiento Determina el sitio en que se guarda el objeto y su

duracioacuten ( 213 ) 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 disquisicioacuten respecto a si un mismo objeto Por ejemplo una variable puede estar referenciado por dos identificadores distintos (que se refieren a la misma regioacuten de memoria) En la mayoriacutea de lenguajes de programacioacuten esta distincioacuten entre identificador y almacenamiento estaacute perfectamente establecida y suelen proporcionar mecanismos sintaacutecticos para que dos identificadores puedan referirse al mismo almacenamiento

412 Declaraciones y definiciones

sect1 Sinopsis

Utilizando un leacutexico formalista podemos decir que una declaracioacuten es una sentencia que

introduce un nombre en una unidad de compilacioacuten ( 142) daacutendole existencia semaacutentica Esto de la existencia semaacutentica es una forma elegante de decir que a partir de ahiacute el compilador sabe que cosa es (representa) ese nombre La forma de darle existencia semaacutentica a las entidades es declararlos (algo asiacute como presentarlos formalmente en el coacutedigo) Por ejemplo si declaramos una variable x o una funcioacuten func a partir de ahiacute el compilador sabe que x es una variable de tal tipo y que func es una funcioacuten de caracteriacutesticas cuales

El punto importante a resaltar aquiacute es que cada declaracioacuten asocia un nombre con un tipo de dato

lo que en C++ (una sociedad muy clasista 22) es importante ya que el conocimiento del tipo que corresponde a un identificador proporciona al compilador mucha informacioacuten sobre la entidad

representada por este (en muchas ocasiones casi toda la informacioacuten necesaria ) En especial el compilador dispone de una amplia informacioacuten acerca del uso de los tipos baacutesicos que operaciones son permitidas y que significado tienen estas operaciones

No olvidar que una declaracioacuten no hace nada maacutes que esto Es decir no antildeade ninguna otra informacioacuten distinta de relacionar una etiqueta con un tipo Posteriormente cuando esta etiqueta esteacute asociada con una entidad concreta (con una zona de memoria) las operaciones permitidas se

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

compila con la opcioacuten -A para compatibilidad ANSI la secuencia de escape es traducida por el compilador a

sect3 Como hemos sentildealado en C++ las cadenas alfanumeacutericas son teacutecnicamente matrices de caracteres constantes se almacenan internamente como secuencias de caracteres maacutes un caraacutecter final nulo 0 lo que significa que el almacenamiento usado es igual a la longitud visible de la cadena mas uno Seguacuten esto la cadena nula es almacenada como un solo caraacutecter 0 y no hay maacutes liacutemite que la memoria disponible para la longitud posible de una cadena Por ejemplo la cadena Holan se guarda internamente como

H o l a n 0

Nota histoacuterica El meacutetodo de identificar el final de cadena mediante un caraacutecter nulo es ineficiente y aparte de que no permite utilizar cadenas que contengan un caraacutecter nulo en su interior (por ejemplo ficheros binarios) su manejo conlleva problemas de rendimiento [3]

Aparentemente la razoacuten por la que C y C++ utilizan este meacutetodo se debe a que C se desarrolloacute

sobre maacutequinas Unix ( 1 ) y a su vez este sistema operativo fue desarrollado inicialmente sobre una maacutequina DEC (Digital Equipment Corporation) PDP-7 que teniacutean un tipo de dato denominado ASICZ (ASCII con un Zero al final) que era directamente reconocible por su ensamblador

sect4 Peculiaridades

En el preaacutembulo sentildealamos 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 ninguacuten 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 uacutenica singularidad es que el compilador C++ les permite ciertas formas particulares de definicioacuten y declaracioacuten que les confiere cierta personalidad

Por ejemplo el hecho de inicializarlas directamente con expresiones como las sentildealadas sect12 o que antildeada automaacuteticamente el caraacutecter nulo de terminacioacuten a los caracteres expliacutecitamente indicados por el programador

Respecto a esto uacuteltimo solo tiene justificacioacuten histoacuterica porque el caraacutecter nulo se utilizaba en las antiguas funciones de libreriacutea para indicar el final de la cadena Por esta razoacuten aunque es posible incluir caracteres nulos dentro de las cadenas literales Por ejemplo Hola0 mundo no estaacute garantizado que funcione en todos los casos (seraacute malinterpretado por las funciones printf strcpy y strlen de la Libreriacutea Estaacutendar)

Ejemplo

char ptr = Hola0 mundoprintf(sn ptr)

Salida

Hola

sect5 Una cadena nula (vaciacutea) se representa o 0 tiene un solo caraacutecter el caraacutecter nulo (ver a continuacioacuten) Observe que desde el punto de vista del Rvalue la constante de cadena A es A

0 mientras que la constante caraacutecter ( 323d) A es A

Se considera que la longitud de un NTBS es el nuacutemero de caracteres que preceden al de terminacioacuten de forma que la cadena nula tiene longitud 0 (aunque en realidad contiene un caraacutecter) Sin embargo el valor de la cadena incluye el caraacutecter de final

Conviene no confundir una constante de cadena (matriz) de un solo caraacutecter con un

caraacutecter char constante ( 323d) o variable ( 221a) La cadena de un solo caraacutecter es necesariamente la cadena nula su uacutenico elemento es el de fin de cadena Ejemplo

char x1= a L1 variable x1 tipo char valor == ASCII a == 97 decimalconst char x2= a L2 constante x2 tipo const charchar x3 = a L3 variable x3 tipo puntero-a-char sentildeala a cadena de dos caracteres 97 y 0 decimalconst char x4 = a L4 variable x4 tipo puntero a constante caraacutecterchar x5[1]= a L5 variable x5 tipo matriz de un caraacutecter valor x[0]== a == 97 decimal

Los objetos representados por los Rvalues ( 215) de las expresiones anteriores son de distinto tipo y se almacenan con tamantildeos distintos La primera segunda y quinta son constantes caraacutecter (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 tambieacuten muy importante sentildealar que la asignacioacuten

str = AEIOU

solo es posible si str se ha declarado previamente como puntero a caraacutecter es decir

char str sectg

Aunque se puede declarar y definir en la misma sentencia (preferible)

char str = AEIOU secth

El lector observador advertiraacute en la expresioacuten anterior una evidente inconsistencia en la gramaacutetica del C++ En efecto como se ha sentildealado las cadenas literales son de caracteres constantes En

consecuencia no asignables a punteros tales como los definidos en sectg o secth teacutecnicamente punteros a caraacutecter Teoacutericamente solo hubiese sido aceptable la asignacioacuten a puntero-a-caraacutecter-constante tal como

const char str = AEIOU secti

ya que un puntero-a-constante-tipoX no es intercambiable por un puntero-a-tipoX ( 421a) La razoacuten de esta inconsistencia en la definicioacuten de las cadenas literales hay que buscarla en otra de las desafortunadas herencias del C claacutesico y en la necesidad de mantener compatibilidad con millones de liacuteneas de coacutedigo existente En C y en las primitivas versiones de C++ las cadenas literales eran consideradas como de tipo char (puntero a caraacutecter)

Aunque la mayoriacutea de compiladores C++ permiten este tipo de sentencias por razones de tipo histoacuterico parece que tal permisividad tiende a ser deprecated (a extinguir) de forma que las uacuteltimas revisiones de algunos compiladores pueden lanzar una advertencia o error en tales circunstancias La forma canoacutenica de definir este tipo de cadenas seriacutea

const char str[] = AEIOU

La expresioacuten secth define una matriz de seis caracteres constantes (almacenado en alguacuten sitio) que no tiene identificador simple (nombre) Tambieacuten define un puntero str al primer elemento de la matriz (maacutes formalmente es un puntero a caraacutecter) Por tanto a falta de un nombre la matriz tiene que ser accedida a traveacutes del puntero (que tendraacute que ser tratado como tal -puntero-) Sin embargo las expresiones

char arr[] = AEIOU sectjchar arr[6] = AEIOUchar arr[6] = AEIOU0char arr[6] = AEIOUchar arr[6] = AEIOU0

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 (secth ) str es un puntero un objeto que puede ser usado con el aacutelgebra de punteros Por ejemplo es vaacutelida la expresioacuten str++ que

equivale a str = str+1 En los otros cinco casos (sectj ) arr es un nemoacutenico que representa una matriz y la expresioacuten arr++ que equivale a arr = arr+1 es ilegal El operando arr+1 es tratado como (amparr[0])+1 lo que es correcto (a un puntero se le puede sumar un entero) La asignacioacuten no seriacutea correcta porque intentariacutea asignar el puntero amparr[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 asignacioacuten 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 asignacioacuten del tipo x = aeiou Si tiene en cambio poderosas funciones en su Libreriacutea Estaacutendar para hacer todo tipo de manipulaciones con cadenas alfanumeacutericas

Es tambieacuten importante distinguir otra diferencia entre las expresiones

char a1[6] = AEIOU0 p1 = ampa1[0]char a2 = AEIOU

Ambas producen matrices de caracteres absolutamente ideacutenticos en contenido y tamantildeo pero a1 es una matriz por lo que sus elementos podriacutean ser alterados usando el identificador Por ejemplo es vaacutelido a1[1]= e o su equivalente (p1+1)=e En cambio un intento anaacutelogo sobre el segundo obliga a usar necesariamente la versioacuten con puntero (a2+1)=e Ademaacutes de que por las razones ya expuestas [2] el resultado no estaacute 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 todaviacutea la asignacioacuten

a2 = aeiou

En este caso el compilador almacena en alguacuten sitio la cadena aeiou0 y asigna a a2 la direccioacuten 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 ninguacuten modo aunque sigue malgastando espacio de memoria

Tambieacuten es posible declarar cadenas de caracteres anchos con el prefijo L como en el ejemplo

wchar_t wptr = Laeiou

en este caso wptr sentildeala una cadena de caracteres anchos ( 221a1) la cadena es del tipo const wchar_t

Para saber la longitud de una constante literal es necesario que el programa repase la cadena hasta encontrar el caraacutecter de fin de cadena lo que se consigue con la funcioacuten de libreriacutea strlen (incluida en la cabecera estaacutendar ltstringhgt) que proporciona la longitud sin contar el caraacutecter final

sect6 Concatenacioacuten de cadenas

Las cadenas literales adyacentes separadas solo por un especio son automaacuteticamente

concatenadas durante la fase de preprocesado ( 141) de la compilacioacuten Por ejemplo Hola mundo es equivalente a Hola mundo Tambieacuten puede usarse la barra invertida ( ) como siacutembolo de continuacioacuten para extender una cadena literal maacutes allaacute del liacutemite de una liacutenea

puts(En realidad esto es una cadena de una linea)char p = Esto es en otra cadena tambieacuten de una sola liacutenea

La concatenacioacuten suprime el caraacutecter nulo de final en las cadenas intermedias y mantiene el de la uacuteltima Esta operacioacuten no altera el significado de los caracteres que intervienen en las cadenas concatenadas Por ejemplo la concatenacioacuten

xA B

Produce la cadena

xAB

que tiene tres caracteres el hexadecimal xA el caraacutecter B y el caracter final nulo 0 En vez del caraacutecter hexadecimal xAB

La concatenacioacuten de cadenas anchas y estrechas tiene resultados impredecibles

323g Constantes de enumeracioacuten

sect1 Sinopsis

Existe un tipo especial de variables denominadas variables enumeradas o

simplemente enumeraciones ( 48 ) Se caracterizan por poder adoptar valores entre una seleccioacuten de constantes enteras denominadas enumeradores cuyos valores son establecidos en el momento de la declaracioacuten del nuevo tipo Como se ha sentildealado son enteros y (una vez establecidos) de valor constante razoacuten por la que se los denomina tambieacuten constantes de enumeracioacuten

Ejemplo

enum estado MALO =0 REGULAR =1 BUENO =2 EXTRA =3

La sentencia anterior declara estado como un tipo de variable de enumeracioacuten Los miembros de esta clase pueden adoptar los valores indicados y son representados por los nemoacutenicos MALO REGULAR BUENO y EXTRA Estas cuatro constantes son los enumeradores del nuevo tipo

Como advertencia a lo indicado hasta aquiacute no confundir la enumeracioacuten (la variable) con los enumeradores (las constantes enteras que delimitan el conjunto de valores posibles de la variable) Tambieacuten 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 = EXTRAestado tu_estado = REGULAR stdcout ltlt Mi estado actual es ltlt mi_estado ltlt endl -gt Mi estado actual es 3

En el caso anterior estado es una enumeracioacuten (tipo geneacuterico) 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 (geneacuterico) con un tipo enum concreto una instancia (variable enumerada) de ese tipo ni con los valores concretos (constantes de enumeracioacuten) que puede adoptar

Para facilitar la legibilidad los identificadores de las constantes de enumeracioacuten son nemoacutenicos y sus nombres suelen estar en mayuacutesculas debido a una larga tradicioacuten CC++ de representar de este modo las constantes

Ya hemos sentildealado que estas constantes (enumeradores) son de tipo entero por lo que pueden ser utilizadas en cualquier expresioacuten donde sean permitidas las constantes enteras Sus identificadores deben ser uacutenicos dentro del aacutembito de la declaracioacuten enum Se permiten inicializadores negativos los valores que adoptan los enumeradores suelen ser uacutenicos (aunque se permiten duplicidades) Para una visioacuten maacutes detallada de las declaraciones de estas constantes

ver enumeraciones ( 48 ) y la explicacioacuten que sigue sobre la palabra clave enum

sect2 Sintaxis

enum [ltnombre-de-tipogt] ltnombr-constgt [= ltvalorgt] [lista_var]

Puede omitirse la palabra clave enum siempre que el nemoacutenico ltnombre-de-tipogt no sea empleado para nada maacutes en el mismo aacutembito Ejemplo

calidad BUENA REGULAR MALA

En este caso el compilador presupone que calidad es un enumerador y no debe existir otra

definicioacuten en el mismo aacutembito de nombres En otras palabras calidad no debe utilizarse en el mismo aacutembito para designar otro objeto

ltnombre-de-tipogt es una etiqueta opcional que identifica al conjunto Puede omitirse si no se va a usar ninguna otra variable de este tipo de enumeracioacuten Ejemplo

enum CIERTO DUDOSO FALSO

ltnombr-constgt es el nombre de la constante de enumeracioacuten (enumerador) a la que opcionalmente puede asignarse el valor definido porltvalorgt En el ejemplo anterior son tres CIERTO DUDOSO y FALSO

ltvalorgt debe ser un entero (ya se ha sentildealado que los enumeradores son constantes

enteras) Si no se especifica ninguacuten valor se supone que es ltpreviogt + 1 donde ltpreviogt es el valor del enumerador anterior de la lista (el valor por defecto para el primero es cero) ltvalorgtpuede ser cualquier expresioacuten que resulte en un entero positivo o negativo (despueacutes de posible conversioacuten a entero)

ltlista_vargt 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 enumeracioacuten de nombre geneacuterico calidad las variables de este tipo pueden adoptar tres valores 0 1 y 2 identificados respectivamente por los nemoacutenicos BUENO REGULAR y MALO ademaacutes se definen dos variables del nuevo

tipo nota yestado

enum calidad BUENO REGULAR MALO nota estado

sect3 Descripcioacuten

La palabra clave enum define una enumeracioacuten 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 nemoacutenicos Por ejemplo la declaracioacuten

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 nemoacutenicos DOM LUNSAB Ademaacutes 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 nemoacutenicos ULT BW40 C40 BW80 C80 y MONO

Los valores asignados a los enumeradores dependen del formato de la declaracioacuten 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 Ademaacutes como puede comprobarse las expresiones de inicializacioacuten pueden incluir enumeradores previamente declarados

Los valores de los enumeradores no tienen porqueacute ser uacutenicos como en el ejemplo que sigue

enum estado BUENO MALO = 1 REGULAR = 1

326 Puntuadores

sect1 Sinopsis

Los signos de puntuacioacuten del lenguaje C++ juegan el mismo papel que sus homoacutenimos en el lenguaje natural escrito Conocidos tambieacuten comopuntuadores [1] son los que se citan a continuacioacuten La mayoriacutea de ellos tienen un doble uso y en ocasiones funcionan tambieacuten

comooperadores ( 49)

[ ] ( ) = ^ amp ndash + | ~ lt gt

sect2 Corchetes [ ]

Los corchetes indican subiacutendices de matrices uni y multi dimensionales

char ch str[] = Cadena de caracteresint mat[3][4] Matriz de 3 x 4ch = str[3] cuarto elemento

sect3 Pareacutentesis ( )

Los pareacutentesis sirven para agrupar expresiones alterar la precedencia normal de los operadores y su asociatividad aislar expresiones condicionales indicar llamadas a funciones y sentildealar los paraacutemetros de estas La sintaxis de C++ exige indefectiblemente el uso de pareacutentesis en muacuteltiples ocasiones En los ejemplos que siguen se muestran algunos usos

d = c (a + b) modifica la precedencia normalif (d == z) ++x imprescindible en la sentencia iffor (x =1 xlt10 x++) imprescindible en la sentencia forfunc() sentildeala llamada a funcioacutenint func() declara funcioacutenint (fptr)() declara puntero a funcioacutenfptr = func asigna valor al puntero

Observe que en el uacuteltimo caso la ausencia de pareacutentesis equivale a ampfunc ( 424a )

Se recomienda el uso de pareacutentesis en las macro-definiciones para evitar problemas potenciales en la expansioacuten Por ejemplo

define CUBO(x) ((x) (x) (x))

sect4 Llaves

Los pares de llaves sentildealan el comienzo y final de una sentencia compuesta es decir bloques de coacutedigo (grupos de sentencias que son tratadas como una unidad) Constituyen el segundo paso (despueacutes de las sentencias) en la estructuracioacuten y compartimentacioacuten del coacutedigo C++

if (d == z) ++x func()

Un bloque es una sentencia compuesta se trata de una sucesioacuten (que puede estar vaciacutea) de sentencias delimitadas por un par de corchetes Desde el punto de vista sintaacutectico un bloque puede ser considerado como una sola sentencia Juega un papel importante en el aacutembito (scope) de los identificadores puesto que un identificador declarado dentro de un bloque tiene un aacutembito

que comienza en el punto de la declaracioacuten 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)

Despueacutes del corchete de cierre no se necesita el punto y coma de fin de sentencia

if (statement) punto y coma ilegal else

Nota las llaves sirven tambieacuten en C++ para otros usos distintos de la pura delimitacioacuten de bloques de coacutedigo Por ejemplo en la definicioacuten de estructuras uniones y clases en cuyo caso si puede ser necesaria la inclusioacuten del punto y coma despueacutes de la llave de cierre

sect5 Coma

La coma como puntuador se utiliza para separar los elementos en las listas de paraacutemetros de una funcioacuten

void func(int n float f char ch)

La coma se usa tambieacuten como un operador en las expresiones con coma ( 4105) Es posible mezclar los dos usos (separador en lista de paraacutemetros y operador) pero deben usarse pareacutentesis para distinguirlos

sect6 Punto y coma

El punto y coma es el signo de fin de sentencia Cualquier expresioacuten legal C++ terminada por un punto y coma (incluyendo la expresioacuten vaciacutea - un punto y coma aislado-) es interpretado como una

sentencia conocidas como sentencia-expresioacuten ( 410) La expresioacuten se evaluacutea y el resultado se descarta si no tiene efectos colaterales C++ la ignora

a + b evaluacutea a + b descarta el resultado++a efecto lateral en a se descarta el valor ++a expresioacuten vaciacutea = sentencia nula

El punto y coma se usa a veces para crear sentencias nulas

for (i = 0 i lt n i++) sentencia nula (hacer nada)

sect7 Dos puntos

Los dos puntos se utilizan para sentildealar sentencias etiquetadas ( 4101)

comienzo x=0 comienzo es la etiquetagoto comienzo

sect8 Puntos suspensivos

Los puntos suspensivos tambieacuten 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 nuacutemero variable de argumentos o pueden ser de tipo variable ( 441) Por ejemplo

void func(int n char ch)

Este prototipo de funcioacuten declara que func estaacute definida de modo que debe ser llamada con al

menos dos argumentos un int y un char Ademaacutes puede tener un cierto nuacutemero de argumentos adicionales (puede omitirse la coma antes de la elipsis)

Se utiliza tambieacuten para indicar que un manejador de excepciones (handler) puede capturar una

excepcioacuten de cualquier tipo ( 162) Ejemplo

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

Nota como podeacuteis ver en ocasiones mi uso particular en los ejemplos de los tres puntos es para indicar cualquier nuacutemero de sentencias Espero que no sea motivo de confusioacuten Desde luego en el caso anterior seriacutea maacutes correcta la notacioacuten

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

sect9 Asterisco

El asterisco puede ser utilizado en C++ de tres formas como una declaracioacuten de tipo de variable

(variable de puntero 42 ) como operador de indireccioacuten (tambieacuten llamado operador

de dereferencia 4911a) y como operador de multiplicacioacuten

Ejemplos

char char_ptr declara puntero a caraacutecterx = int_ptr operador de indireccioacutenl = 2 314 r operador multiplicacioacuten

sect10 Signo igual =

El signo igual = separa la declaracioacuten de variables de las listas de inicializacioacuten

char array[5] = 1 2 3 4 5

Recordemos que al contrario que en C donde las declaraciones no pueden estar precedidas por ninguacuten coacutedigo deben ir al principio en C++ las declaraciones de cualquier tipo pueden aparecer en cualquier punto del coacutedigo (con algunas restricciones)

En la lista de argumentos de una funcioacuten el signo igual indica el valor por defecto para un paraacutemetro

int f(int i = 0) el valor por defecto de k es cero

El signo igual es tambieacuten utilizado como operador de asignacioacuten ( 492) Ejemplo

x = yz += 5

sect11 Almohadilla

Si la almohadilla aparecen en el primer caraacutecter (distinto de espacio en blanco) de una liacutenea

sentildeala directivas de preproceso ( 4910) En este caso es un operador especiacutefico de la fase

de preproceso del coacutedigo fuente Significa una opcioacuten del preprocesador ( 14) que no tiene porqueacute estar asociada necesariamente a generacioacuten de coacutedigo Las directivas se situacutean generalmente al comienzo del programa aunque legalmente pueden aparecer en cualquier punto

Ejemplos de directivas de preproceso

(null directive)define NULO 0include ltstdiohgt

4 Estructura del lenguaje

sect1 Sinopsis

Esta parte proporciona una definicioacuten formal del lenguaje C++ describiendo las formas en que

pueden agruparse correctamente los tokens ( 32) palabras que constituyen el lenguaje entendible por el compilador para formar declaraciones expresiones y otras unidades significativas Para su anaacutelisis lo hemos descompuesto en 13 grupos seguacuten la clasificacioacuten que sigue

sect41 Declaraciones

ObjetosReferencias amp definicionesDefinicioacuten provisionalAacutembitoVisibilidadDuracioacutenUnidad de compilacioacutenEnlazado

Sintaxis de declaraciones

Conversiones aritmeacuteticasInicializacioacutenEspecificadores de clase de almacenamientoModificadores auxiliaresModificadores de funcioacuten

sect42 Punteros

Puntero a objetoDeclaracioacuten de punterosAritmeacutetica de punterosReferenciasPuntero a funcioacuten

sect43 Matrices

Declaracioacuten de matricesMatrices alfanumeacutericasMatrices de punterosMatrices de matrices

sect44 Funciones

DeclaracioacutenDefinicioacutenArgumentos formales y actualesLlamada y conversioacuten de argumentosValores devueltos

sect45 Estructuras

Declaracioacuten de estructurasInicializacioacutenOperaciones permitidasAcceso a miembrosEstructuras y funcionesMatrices de estructurasPunteros a estructurasEstructuras auto-referenciadas

sect46 Campos de Bits

sect47 Uniones

sect48 Enumeraciones

Expresiones

Asociatividad y precedencia de operadoresOrden de evaluacioacutenErrores y desbordamientosExpresiones con coma

sect49 Operadores

AritmeacuteticosAsignacioacutenManejo de BitsOperador ComaCondicionalOp de igualdadOp LoacutegicosModelado de tiposOp de PreprocesoOp de punteroRelacionalessizeoftypeidOp primariosOp antildeadidosOp UnitariosSobrecarga de OperadoresOperador Operador newOperador delete

sect410 Sentencias

Sentencias de etiqueta case defaultSentencias de seleccioacuten if hellip else else if switchSentencias de iteracioacuten while dowhile forSentencias de salto break continue goto return

sect411 Clases

CreacioacutenDeclaracioacutenNombres de ClasesAacutembito de nombresInstanciado de Clasesthis (palabra reservada)Miembros estaacuteticosClases polimoacuterficasFunciones virtualesFunciones dinaacutemicasClases abstractas

sect412 Plantillas

Funciones geneacutericasClases geneacutericas

Aunque las secciones anteriores describen completamente el lenguaje desde una perspectiva formal hemos antildeadido un capiacutetulo adicional (sect413) dedicado a los tecnicismos En eacutel se incluyen algunos consejos y reglas de buena praacutectica para la programacioacuten C++ asiacute como algunos idioms

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

41 Declaraciones

sect1 Sinopsis

Una declaracioacuten es una claacuteusula que introduce nombres en una unidad de compilacioacuten ( 142) o redeclara nombres introducidos por declaraciones previas La norma sentildeala que una declaracioacuten especifica la interpretacioacuten y atributos de estos nombres (como tipo de enlazado y de almacenamiento si es un objeto) asiacute como las condiciones para que una declaracioacuten no sea

tambieacuten una definicioacuten En la paacutegina adjunta se muestra su gramaacutetica ( Gramaacutetica)

Cada una de las introducciones unitarias que puede existir en una declaracioacuten es un declarador (declarator) Asiacute pues un declarador introduce un nombre o redeclara uno

declarado previamente La paacutegina adjunta muestra su gramaacutetica ( Gramaacutetica)

El presente capiacutetulo repasa este importante concepto y otros relacionados tales como objetos clases de almacenamiento tipos aacutembitovisibilidad duracioacuten y enlazado

El aacutembito visibilidad duracioacuten y enlazado son propiedades o caracteriacutesticas 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 definicioacuten de declaracioacuten o la exposicioacuten de su sintaxis

En el epiacutegrafe 4111 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 tambieacuten es dada a conocer mediante una declaracioacuten

411 Entidades

sect1 Presentacioacuten

En relacioacuten con los conceptos que aquiacute nos incumben consideramos que una entidad ( 121) 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 objeto-valor

Un algoritmo con informacioacuten sobre manipulacioacuten de datos Lo denominamos entidad-algoritmo o simplemente algoritmo

Respecto a los objetos-valor una posible clasificacioacuten podriacutea dividirlos en las siguientes categoriacuteas

Agregados

o matrizo estructurao unioacuteno clase unioacuten

Funciones Escalares

o Aritmeacuteticoo Enumeracioacuteno Booleanoo Punteroo Referencia

void

void ( 221) es un tipo especial con un valor muy particular ausencia de valor Los escalares son de caracteriacutesticas tales que su valor no pueden ser descompuestos en partes maacutes pequentildeas

por ejemplo un entero un valor loacutegico (cierto-falso) etc Las funciones ( 44) son principalmente algoritmo ya que estaacuten asociadas a ciertas operaciones (cierta computacioacuten) pero por convencioacuten se les puede asignar un valor es el que devuelven (puede ser void) Por su parte los agregados comparten la caracteriacutestica de que su valor puede ser descompuesto en elementos maacutes simples (escalares)

sect2 El papel de las declaraciones

Haciendo un siacutemil social podriacuteamos decir que las declaraciones son las encargadas de presentar al compilador cualquier entidad que deba existir en el programa Son por tanto el Chambelaacuten de la sociedad C++ Como en el caso de las presentaciones sociales esta presentacioacuten no se reduce a indicar el nombre tambieacuten puede sentildealarse algunas caracteriacutesticas 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

sect3 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 expresioacuten compleja que

represente uniacutevocamente al objeto ( 211 ) Cualquier intento de utilizar una declaracioacuten sin un nombre es un error aunque el nombre no tiene que responder necesariamente a un objeto o funcioacuten Ejemplo

extern int Errorchar Errorchar cptr Ok cptr nombre de punteroclass C Ok C nombre de clasetypedef unsigned int UINT Ok UINT alias para un tipo conocido

Ademaacutes del identificador las declaraciones de funciones pueden incluir ciertos atributos inline ( 4112a) virtual ( 4118a) y explicit ( 4112d1)

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 ( 21 ) Entre otros puede incluir los siguientes char wchar_t bool short int long signed unsigned float double void

Relativos al tipo de almacenamiento Determina el sitio en que se guarda el objeto y su

duracioacuten ( 213 ) 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 disquisicioacuten respecto a si un mismo objeto Por ejemplo una variable puede estar referenciado por dos identificadores distintos (que se refieren a la misma regioacuten de memoria) En la mayoriacutea de lenguajes de programacioacuten esta distincioacuten entre identificador y almacenamiento estaacute perfectamente establecida y suelen proporcionar mecanismos sintaacutecticos para que dos identificadores puedan referirse al mismo almacenamiento

412 Declaraciones y definiciones

sect1 Sinopsis

Utilizando un leacutexico formalista podemos decir que una declaracioacuten es una sentencia que

introduce un nombre en una unidad de compilacioacuten ( 142) daacutendole existencia semaacutentica Esto de la existencia semaacutentica es una forma elegante de decir que a partir de ahiacute el compilador sabe que cosa es (representa) ese nombre La forma de darle existencia semaacutentica a las entidades es declararlos (algo asiacute como presentarlos formalmente en el coacutedigo) Por ejemplo si declaramos una variable x o una funcioacuten func a partir de ahiacute el compilador sabe que x es una variable de tal tipo y que func es una funcioacuten de caracteriacutesticas cuales

El punto importante a resaltar aquiacute es que cada declaracioacuten asocia un nombre con un tipo de dato

lo que en C++ (una sociedad muy clasista 22) es importante ya que el conocimiento del tipo que corresponde a un identificador proporciona al compilador mucha informacioacuten sobre la entidad

representada por este (en muchas ocasiones casi toda la informacioacuten necesaria ) En especial el compilador dispone de una amplia informacioacuten acerca del uso de los tipos baacutesicos que operaciones son permitidas y que significado tienen estas operaciones

No olvidar que una declaracioacuten no hace nada maacutes que esto Es decir no antildeade ninguna otra informacioacuten distinta de relacionar una etiqueta con un tipo Posteriormente cuando esta etiqueta esteacute asociada con una entidad concreta (con una zona de memoria) las operaciones permitidas se

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

sect5 Una cadena nula (vaciacutea) se representa o 0 tiene un solo caraacutecter el caraacutecter nulo (ver a continuacioacuten) Observe que desde el punto de vista del Rvalue la constante de cadena A es A

0 mientras que la constante caraacutecter ( 323d) A es A

Se considera que la longitud de un NTBS es el nuacutemero de caracteres que preceden al de terminacioacuten de forma que la cadena nula tiene longitud 0 (aunque en realidad contiene un caraacutecter) Sin embargo el valor de la cadena incluye el caraacutecter de final

Conviene no confundir una constante de cadena (matriz) de un solo caraacutecter con un

caraacutecter char constante ( 323d) o variable ( 221a) La cadena de un solo caraacutecter es necesariamente la cadena nula su uacutenico elemento es el de fin de cadena Ejemplo

char x1= a L1 variable x1 tipo char valor == ASCII a == 97 decimalconst char x2= a L2 constante x2 tipo const charchar x3 = a L3 variable x3 tipo puntero-a-char sentildeala a cadena de dos caracteres 97 y 0 decimalconst char x4 = a L4 variable x4 tipo puntero a constante caraacutecterchar x5[1]= a L5 variable x5 tipo matriz de un caraacutecter valor x[0]== a == 97 decimal

Los objetos representados por los Rvalues ( 215) de las expresiones anteriores son de distinto tipo y se almacenan con tamantildeos distintos La primera segunda y quinta son constantes caraacutecter (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 tambieacuten muy importante sentildealar que la asignacioacuten

str = AEIOU

solo es posible si str se ha declarado previamente como puntero a caraacutecter es decir

char str sectg

Aunque se puede declarar y definir en la misma sentencia (preferible)

char str = AEIOU secth

El lector observador advertiraacute en la expresioacuten anterior una evidente inconsistencia en la gramaacutetica del C++ En efecto como se ha sentildealado las cadenas literales son de caracteres constantes En

consecuencia no asignables a punteros tales como los definidos en sectg o secth teacutecnicamente punteros a caraacutecter Teoacutericamente solo hubiese sido aceptable la asignacioacuten a puntero-a-caraacutecter-constante tal como

const char str = AEIOU secti

ya que un puntero-a-constante-tipoX no es intercambiable por un puntero-a-tipoX ( 421a) La razoacuten de esta inconsistencia en la definicioacuten de las cadenas literales hay que buscarla en otra de las desafortunadas herencias del C claacutesico y en la necesidad de mantener compatibilidad con millones de liacuteneas de coacutedigo existente En C y en las primitivas versiones de C++ las cadenas literales eran consideradas como de tipo char (puntero a caraacutecter)

Aunque la mayoriacutea de compiladores C++ permiten este tipo de sentencias por razones de tipo histoacuterico parece que tal permisividad tiende a ser deprecated (a extinguir) de forma que las uacuteltimas revisiones de algunos compiladores pueden lanzar una advertencia o error en tales circunstancias La forma canoacutenica de definir este tipo de cadenas seriacutea

const char str[] = AEIOU

La expresioacuten secth define una matriz de seis caracteres constantes (almacenado en alguacuten sitio) que no tiene identificador simple (nombre) Tambieacuten define un puntero str al primer elemento de la matriz (maacutes formalmente es un puntero a caraacutecter) Por tanto a falta de un nombre la matriz tiene que ser accedida a traveacutes del puntero (que tendraacute que ser tratado como tal -puntero-) Sin embargo las expresiones

char arr[] = AEIOU sectjchar arr[6] = AEIOUchar arr[6] = AEIOU0char arr[6] = AEIOUchar arr[6] = AEIOU0

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 (secth ) str es un puntero un objeto que puede ser usado con el aacutelgebra de punteros Por ejemplo es vaacutelida la expresioacuten str++ que

equivale a str = str+1 En los otros cinco casos (sectj ) arr es un nemoacutenico que representa una matriz y la expresioacuten arr++ que equivale a arr = arr+1 es ilegal El operando arr+1 es tratado como (amparr[0])+1 lo que es correcto (a un puntero se le puede sumar un entero) La asignacioacuten no seriacutea correcta porque intentariacutea asignar el puntero amparr[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 asignacioacuten 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 asignacioacuten del tipo x = aeiou Si tiene en cambio poderosas funciones en su Libreriacutea Estaacutendar para hacer todo tipo de manipulaciones con cadenas alfanumeacutericas

Es tambieacuten importante distinguir otra diferencia entre las expresiones

char a1[6] = AEIOU0 p1 = ampa1[0]char a2 = AEIOU

Ambas producen matrices de caracteres absolutamente ideacutenticos en contenido y tamantildeo pero a1 es una matriz por lo que sus elementos podriacutean ser alterados usando el identificador Por ejemplo es vaacutelido a1[1]= e o su equivalente (p1+1)=e En cambio un intento anaacutelogo sobre el segundo obliga a usar necesariamente la versioacuten con puntero (a2+1)=e Ademaacutes de que por las razones ya expuestas [2] el resultado no estaacute 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 todaviacutea la asignacioacuten

a2 = aeiou

En este caso el compilador almacena en alguacuten sitio la cadena aeiou0 y asigna a a2 la direccioacuten 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 ninguacuten modo aunque sigue malgastando espacio de memoria

Tambieacuten es posible declarar cadenas de caracteres anchos con el prefijo L como en el ejemplo

wchar_t wptr = Laeiou

en este caso wptr sentildeala una cadena de caracteres anchos ( 221a1) la cadena es del tipo const wchar_t

Para saber la longitud de una constante literal es necesario que el programa repase la cadena hasta encontrar el caraacutecter de fin de cadena lo que se consigue con la funcioacuten de libreriacutea strlen (incluida en la cabecera estaacutendar ltstringhgt) que proporciona la longitud sin contar el caraacutecter final

sect6 Concatenacioacuten de cadenas

Las cadenas literales adyacentes separadas solo por un especio son automaacuteticamente

concatenadas durante la fase de preprocesado ( 141) de la compilacioacuten Por ejemplo Hola mundo es equivalente a Hola mundo Tambieacuten puede usarse la barra invertida ( ) como siacutembolo de continuacioacuten para extender una cadena literal maacutes allaacute del liacutemite de una liacutenea

puts(En realidad esto es una cadena de una linea)char p = Esto es en otra cadena tambieacuten de una sola liacutenea

La concatenacioacuten suprime el caraacutecter nulo de final en las cadenas intermedias y mantiene el de la uacuteltima Esta operacioacuten no altera el significado de los caracteres que intervienen en las cadenas concatenadas Por ejemplo la concatenacioacuten

xA B

Produce la cadena

xAB

que tiene tres caracteres el hexadecimal xA el caraacutecter B y el caracter final nulo 0 En vez del caraacutecter hexadecimal xAB

La concatenacioacuten de cadenas anchas y estrechas tiene resultados impredecibles

323g Constantes de enumeracioacuten

sect1 Sinopsis

Existe un tipo especial de variables denominadas variables enumeradas o

simplemente enumeraciones ( 48 ) Se caracterizan por poder adoptar valores entre una seleccioacuten de constantes enteras denominadas enumeradores cuyos valores son establecidos en el momento de la declaracioacuten del nuevo tipo Como se ha sentildealado son enteros y (una vez establecidos) de valor constante razoacuten por la que se los denomina tambieacuten constantes de enumeracioacuten

Ejemplo

enum estado MALO =0 REGULAR =1 BUENO =2 EXTRA =3

La sentencia anterior declara estado como un tipo de variable de enumeracioacuten Los miembros de esta clase pueden adoptar los valores indicados y son representados por los nemoacutenicos MALO REGULAR BUENO y EXTRA Estas cuatro constantes son los enumeradores del nuevo tipo

Como advertencia a lo indicado hasta aquiacute no confundir la enumeracioacuten (la variable) con los enumeradores (las constantes enteras que delimitan el conjunto de valores posibles de la variable) Tambieacuten 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 = EXTRAestado tu_estado = REGULAR stdcout ltlt Mi estado actual es ltlt mi_estado ltlt endl -gt Mi estado actual es 3

En el caso anterior estado es una enumeracioacuten (tipo geneacuterico) 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 (geneacuterico) con un tipo enum concreto una instancia (variable enumerada) de ese tipo ni con los valores concretos (constantes de enumeracioacuten) que puede adoptar

Para facilitar la legibilidad los identificadores de las constantes de enumeracioacuten son nemoacutenicos y sus nombres suelen estar en mayuacutesculas debido a una larga tradicioacuten CC++ de representar de este modo las constantes

Ya hemos sentildealado que estas constantes (enumeradores) son de tipo entero por lo que pueden ser utilizadas en cualquier expresioacuten donde sean permitidas las constantes enteras Sus identificadores deben ser uacutenicos dentro del aacutembito de la declaracioacuten enum Se permiten inicializadores negativos los valores que adoptan los enumeradores suelen ser uacutenicos (aunque se permiten duplicidades) Para una visioacuten maacutes detallada de las declaraciones de estas constantes

ver enumeraciones ( 48 ) y la explicacioacuten que sigue sobre la palabra clave enum

sect2 Sintaxis

enum [ltnombre-de-tipogt] ltnombr-constgt [= ltvalorgt] [lista_var]

Puede omitirse la palabra clave enum siempre que el nemoacutenico ltnombre-de-tipogt no sea empleado para nada maacutes en el mismo aacutembito Ejemplo

calidad BUENA REGULAR MALA

En este caso el compilador presupone que calidad es un enumerador y no debe existir otra

definicioacuten en el mismo aacutembito de nombres En otras palabras calidad no debe utilizarse en el mismo aacutembito para designar otro objeto

ltnombre-de-tipogt es una etiqueta opcional que identifica al conjunto Puede omitirse si no se va a usar ninguna otra variable de este tipo de enumeracioacuten Ejemplo

enum CIERTO DUDOSO FALSO

ltnombr-constgt es el nombre de la constante de enumeracioacuten (enumerador) a la que opcionalmente puede asignarse el valor definido porltvalorgt En el ejemplo anterior son tres CIERTO DUDOSO y FALSO

ltvalorgt debe ser un entero (ya se ha sentildealado que los enumeradores son constantes

enteras) Si no se especifica ninguacuten valor se supone que es ltpreviogt + 1 donde ltpreviogt es el valor del enumerador anterior de la lista (el valor por defecto para el primero es cero) ltvalorgtpuede ser cualquier expresioacuten que resulte en un entero positivo o negativo (despueacutes de posible conversioacuten a entero)

ltlista_vargt 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 enumeracioacuten de nombre geneacuterico calidad las variables de este tipo pueden adoptar tres valores 0 1 y 2 identificados respectivamente por los nemoacutenicos BUENO REGULAR y MALO ademaacutes se definen dos variables del nuevo

tipo nota yestado

enum calidad BUENO REGULAR MALO nota estado

sect3 Descripcioacuten

La palabra clave enum define una enumeracioacuten 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 nemoacutenicos Por ejemplo la declaracioacuten

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 nemoacutenicos DOM LUNSAB Ademaacutes 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 nemoacutenicos ULT BW40 C40 BW80 C80 y MONO

Los valores asignados a los enumeradores dependen del formato de la declaracioacuten 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 Ademaacutes como puede comprobarse las expresiones de inicializacioacuten pueden incluir enumeradores previamente declarados

Los valores de los enumeradores no tienen porqueacute ser uacutenicos como en el ejemplo que sigue

enum estado BUENO MALO = 1 REGULAR = 1

326 Puntuadores

sect1 Sinopsis

Los signos de puntuacioacuten del lenguaje C++ juegan el mismo papel que sus homoacutenimos en el lenguaje natural escrito Conocidos tambieacuten comopuntuadores [1] son los que se citan a continuacioacuten La mayoriacutea de ellos tienen un doble uso y en ocasiones funcionan tambieacuten

comooperadores ( 49)

[ ] ( ) = ^ amp ndash + | ~ lt gt

sect2 Corchetes [ ]

Los corchetes indican subiacutendices de matrices uni y multi dimensionales

char ch str[] = Cadena de caracteresint mat[3][4] Matriz de 3 x 4ch = str[3] cuarto elemento

sect3 Pareacutentesis ( )

Los pareacutentesis sirven para agrupar expresiones alterar la precedencia normal de los operadores y su asociatividad aislar expresiones condicionales indicar llamadas a funciones y sentildealar los paraacutemetros de estas La sintaxis de C++ exige indefectiblemente el uso de pareacutentesis en muacuteltiples ocasiones En los ejemplos que siguen se muestran algunos usos

d = c (a + b) modifica la precedencia normalif (d == z) ++x imprescindible en la sentencia iffor (x =1 xlt10 x++) imprescindible en la sentencia forfunc() sentildeala llamada a funcioacutenint func() declara funcioacutenint (fptr)() declara puntero a funcioacutenfptr = func asigna valor al puntero

Observe que en el uacuteltimo caso la ausencia de pareacutentesis equivale a ampfunc ( 424a )

Se recomienda el uso de pareacutentesis en las macro-definiciones para evitar problemas potenciales en la expansioacuten Por ejemplo

define CUBO(x) ((x) (x) (x))

sect4 Llaves

Los pares de llaves sentildealan el comienzo y final de una sentencia compuesta es decir bloques de coacutedigo (grupos de sentencias que son tratadas como una unidad) Constituyen el segundo paso (despueacutes de las sentencias) en la estructuracioacuten y compartimentacioacuten del coacutedigo C++

if (d == z) ++x func()

Un bloque es una sentencia compuesta se trata de una sucesioacuten (que puede estar vaciacutea) de sentencias delimitadas por un par de corchetes Desde el punto de vista sintaacutectico un bloque puede ser considerado como una sola sentencia Juega un papel importante en el aacutembito (scope) de los identificadores puesto que un identificador declarado dentro de un bloque tiene un aacutembito

que comienza en el punto de la declaracioacuten 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)

Despueacutes del corchete de cierre no se necesita el punto y coma de fin de sentencia

if (statement) punto y coma ilegal else

Nota las llaves sirven tambieacuten en C++ para otros usos distintos de la pura delimitacioacuten de bloques de coacutedigo Por ejemplo en la definicioacuten de estructuras uniones y clases en cuyo caso si puede ser necesaria la inclusioacuten del punto y coma despueacutes de la llave de cierre

sect5 Coma

La coma como puntuador se utiliza para separar los elementos en las listas de paraacutemetros de una funcioacuten

void func(int n float f char ch)

La coma se usa tambieacuten como un operador en las expresiones con coma ( 4105) Es posible mezclar los dos usos (separador en lista de paraacutemetros y operador) pero deben usarse pareacutentesis para distinguirlos

sect6 Punto y coma

El punto y coma es el signo de fin de sentencia Cualquier expresioacuten legal C++ terminada por un punto y coma (incluyendo la expresioacuten vaciacutea - un punto y coma aislado-) es interpretado como una

sentencia conocidas como sentencia-expresioacuten ( 410) La expresioacuten se evaluacutea y el resultado se descarta si no tiene efectos colaterales C++ la ignora

a + b evaluacutea a + b descarta el resultado++a efecto lateral en a se descarta el valor ++a expresioacuten vaciacutea = sentencia nula

El punto y coma se usa a veces para crear sentencias nulas

for (i = 0 i lt n i++) sentencia nula (hacer nada)

sect7 Dos puntos

Los dos puntos se utilizan para sentildealar sentencias etiquetadas ( 4101)

comienzo x=0 comienzo es la etiquetagoto comienzo

sect8 Puntos suspensivos

Los puntos suspensivos tambieacuten 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 nuacutemero variable de argumentos o pueden ser de tipo variable ( 441) Por ejemplo

void func(int n char ch)

Este prototipo de funcioacuten declara que func estaacute definida de modo que debe ser llamada con al

menos dos argumentos un int y un char Ademaacutes puede tener un cierto nuacutemero de argumentos adicionales (puede omitirse la coma antes de la elipsis)

Se utiliza tambieacuten para indicar que un manejador de excepciones (handler) puede capturar una

excepcioacuten de cualquier tipo ( 162) Ejemplo

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

Nota como podeacuteis ver en ocasiones mi uso particular en los ejemplos de los tres puntos es para indicar cualquier nuacutemero de sentencias Espero que no sea motivo de confusioacuten Desde luego en el caso anterior seriacutea maacutes correcta la notacioacuten

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

sect9 Asterisco

El asterisco puede ser utilizado en C++ de tres formas como una declaracioacuten de tipo de variable

(variable de puntero 42 ) como operador de indireccioacuten (tambieacuten llamado operador

de dereferencia 4911a) y como operador de multiplicacioacuten

Ejemplos

char char_ptr declara puntero a caraacutecterx = int_ptr operador de indireccioacutenl = 2 314 r operador multiplicacioacuten

sect10 Signo igual =

El signo igual = separa la declaracioacuten de variables de las listas de inicializacioacuten

char array[5] = 1 2 3 4 5

Recordemos que al contrario que en C donde las declaraciones no pueden estar precedidas por ninguacuten coacutedigo deben ir al principio en C++ las declaraciones de cualquier tipo pueden aparecer en cualquier punto del coacutedigo (con algunas restricciones)

En la lista de argumentos de una funcioacuten el signo igual indica el valor por defecto para un paraacutemetro

int f(int i = 0) el valor por defecto de k es cero

El signo igual es tambieacuten utilizado como operador de asignacioacuten ( 492) Ejemplo

x = yz += 5

sect11 Almohadilla

Si la almohadilla aparecen en el primer caraacutecter (distinto de espacio en blanco) de una liacutenea

sentildeala directivas de preproceso ( 4910) En este caso es un operador especiacutefico de la fase

de preproceso del coacutedigo fuente Significa una opcioacuten del preprocesador ( 14) que no tiene porqueacute estar asociada necesariamente a generacioacuten de coacutedigo Las directivas se situacutean generalmente al comienzo del programa aunque legalmente pueden aparecer en cualquier punto

Ejemplos de directivas de preproceso

(null directive)define NULO 0include ltstdiohgt

4 Estructura del lenguaje

sect1 Sinopsis

Esta parte proporciona una definicioacuten formal del lenguaje C++ describiendo las formas en que

pueden agruparse correctamente los tokens ( 32) palabras que constituyen el lenguaje entendible por el compilador para formar declaraciones expresiones y otras unidades significativas Para su anaacutelisis lo hemos descompuesto en 13 grupos seguacuten la clasificacioacuten que sigue

sect41 Declaraciones

ObjetosReferencias amp definicionesDefinicioacuten provisionalAacutembitoVisibilidadDuracioacutenUnidad de compilacioacutenEnlazado

Sintaxis de declaraciones

Conversiones aritmeacuteticasInicializacioacutenEspecificadores de clase de almacenamientoModificadores auxiliaresModificadores de funcioacuten

sect42 Punteros

Puntero a objetoDeclaracioacuten de punterosAritmeacutetica de punterosReferenciasPuntero a funcioacuten

sect43 Matrices

Declaracioacuten de matricesMatrices alfanumeacutericasMatrices de punterosMatrices de matrices

sect44 Funciones

DeclaracioacutenDefinicioacutenArgumentos formales y actualesLlamada y conversioacuten de argumentosValores devueltos

sect45 Estructuras

Declaracioacuten de estructurasInicializacioacutenOperaciones permitidasAcceso a miembrosEstructuras y funcionesMatrices de estructurasPunteros a estructurasEstructuras auto-referenciadas

sect46 Campos de Bits

sect47 Uniones

sect48 Enumeraciones

Expresiones

Asociatividad y precedencia de operadoresOrden de evaluacioacutenErrores y desbordamientosExpresiones con coma

sect49 Operadores

AritmeacuteticosAsignacioacutenManejo de BitsOperador ComaCondicionalOp de igualdadOp LoacutegicosModelado de tiposOp de PreprocesoOp de punteroRelacionalessizeoftypeidOp primariosOp antildeadidosOp UnitariosSobrecarga de OperadoresOperador Operador newOperador delete

sect410 Sentencias

Sentencias de etiqueta case defaultSentencias de seleccioacuten if hellip else else if switchSentencias de iteracioacuten while dowhile forSentencias de salto break continue goto return

sect411 Clases

CreacioacutenDeclaracioacutenNombres de ClasesAacutembito de nombresInstanciado de Clasesthis (palabra reservada)Miembros estaacuteticosClases polimoacuterficasFunciones virtualesFunciones dinaacutemicasClases abstractas

sect412 Plantillas

Funciones geneacutericasClases geneacutericas

Aunque las secciones anteriores describen completamente el lenguaje desde una perspectiva formal hemos antildeadido un capiacutetulo adicional (sect413) dedicado a los tecnicismos En eacutel se incluyen algunos consejos y reglas de buena praacutectica para la programacioacuten C++ asiacute como algunos idioms

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

41 Declaraciones

sect1 Sinopsis

Una declaracioacuten es una claacuteusula que introduce nombres en una unidad de compilacioacuten ( 142) o redeclara nombres introducidos por declaraciones previas La norma sentildeala que una declaracioacuten especifica la interpretacioacuten y atributos de estos nombres (como tipo de enlazado y de almacenamiento si es un objeto) asiacute como las condiciones para que una declaracioacuten no sea

tambieacuten una definicioacuten En la paacutegina adjunta se muestra su gramaacutetica ( Gramaacutetica)

Cada una de las introducciones unitarias que puede existir en una declaracioacuten es un declarador (declarator) Asiacute pues un declarador introduce un nombre o redeclara uno

declarado previamente La paacutegina adjunta muestra su gramaacutetica ( Gramaacutetica)

El presente capiacutetulo repasa este importante concepto y otros relacionados tales como objetos clases de almacenamiento tipos aacutembitovisibilidad duracioacuten y enlazado

El aacutembito visibilidad duracioacuten y enlazado son propiedades o caracteriacutesticas 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 definicioacuten de declaracioacuten o la exposicioacuten de su sintaxis

En el epiacutegrafe 4111 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 tambieacuten es dada a conocer mediante una declaracioacuten

411 Entidades

sect1 Presentacioacuten

En relacioacuten con los conceptos que aquiacute nos incumben consideramos que una entidad ( 121) 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 objeto-valor

Un algoritmo con informacioacuten sobre manipulacioacuten de datos Lo denominamos entidad-algoritmo o simplemente algoritmo

Respecto a los objetos-valor una posible clasificacioacuten podriacutea dividirlos en las siguientes categoriacuteas

Agregados

o matrizo estructurao unioacuteno clase unioacuten

Funciones Escalares

o Aritmeacuteticoo Enumeracioacuteno Booleanoo Punteroo Referencia

void

void ( 221) es un tipo especial con un valor muy particular ausencia de valor Los escalares son de caracteriacutesticas tales que su valor no pueden ser descompuestos en partes maacutes pequentildeas

por ejemplo un entero un valor loacutegico (cierto-falso) etc Las funciones ( 44) son principalmente algoritmo ya que estaacuten asociadas a ciertas operaciones (cierta computacioacuten) pero por convencioacuten se les puede asignar un valor es el que devuelven (puede ser void) Por su parte los agregados comparten la caracteriacutestica de que su valor puede ser descompuesto en elementos maacutes simples (escalares)

sect2 El papel de las declaraciones

Haciendo un siacutemil social podriacuteamos decir que las declaraciones son las encargadas de presentar al compilador cualquier entidad que deba existir en el programa Son por tanto el Chambelaacuten de la sociedad C++ Como en el caso de las presentaciones sociales esta presentacioacuten no se reduce a indicar el nombre tambieacuten puede sentildealarse algunas caracteriacutesticas 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

sect3 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 expresioacuten compleja que

represente uniacutevocamente al objeto ( 211 ) Cualquier intento de utilizar una declaracioacuten sin un nombre es un error aunque el nombre no tiene que responder necesariamente a un objeto o funcioacuten Ejemplo

extern int Errorchar Errorchar cptr Ok cptr nombre de punteroclass C Ok C nombre de clasetypedef unsigned int UINT Ok UINT alias para un tipo conocido

Ademaacutes del identificador las declaraciones de funciones pueden incluir ciertos atributos inline ( 4112a) virtual ( 4118a) y explicit ( 4112d1)

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 ( 21 ) Entre otros puede incluir los siguientes char wchar_t bool short int long signed unsigned float double void

Relativos al tipo de almacenamiento Determina el sitio en que se guarda el objeto y su

duracioacuten ( 213 ) 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 disquisicioacuten respecto a si un mismo objeto Por ejemplo una variable puede estar referenciado por dos identificadores distintos (que se refieren a la misma regioacuten de memoria) En la mayoriacutea de lenguajes de programacioacuten esta distincioacuten entre identificador y almacenamiento estaacute perfectamente establecida y suelen proporcionar mecanismos sintaacutecticos para que dos identificadores puedan referirse al mismo almacenamiento

412 Declaraciones y definiciones

sect1 Sinopsis

Utilizando un leacutexico formalista podemos decir que una declaracioacuten es una sentencia que

introduce un nombre en una unidad de compilacioacuten ( 142) daacutendole existencia semaacutentica Esto de la existencia semaacutentica es una forma elegante de decir que a partir de ahiacute el compilador sabe que cosa es (representa) ese nombre La forma de darle existencia semaacutentica a las entidades es declararlos (algo asiacute como presentarlos formalmente en el coacutedigo) Por ejemplo si declaramos una variable x o una funcioacuten func a partir de ahiacute el compilador sabe que x es una variable de tal tipo y que func es una funcioacuten de caracteriacutesticas cuales

El punto importante a resaltar aquiacute es que cada declaracioacuten asocia un nombre con un tipo de dato

lo que en C++ (una sociedad muy clasista 22) es importante ya que el conocimiento del tipo que corresponde a un identificador proporciona al compilador mucha informacioacuten sobre la entidad

representada por este (en muchas ocasiones casi toda la informacioacuten necesaria ) En especial el compilador dispone de una amplia informacioacuten acerca del uso de los tipos baacutesicos que operaciones son permitidas y que significado tienen estas operaciones

No olvidar que una declaracioacuten no hace nada maacutes que esto Es decir no antildeade ninguna otra informacioacuten distinta de relacionar una etiqueta con un tipo Posteriormente cuando esta etiqueta esteacute asociada con una entidad concreta (con una zona de memoria) las operaciones permitidas se

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

const char str = AEIOU secti

ya que un puntero-a-constante-tipoX no es intercambiable por un puntero-a-tipoX ( 421a) La razoacuten de esta inconsistencia en la definicioacuten de las cadenas literales hay que buscarla en otra de las desafortunadas herencias del C claacutesico y en la necesidad de mantener compatibilidad con millones de liacuteneas de coacutedigo existente En C y en las primitivas versiones de C++ las cadenas literales eran consideradas como de tipo char (puntero a caraacutecter)

Aunque la mayoriacutea de compiladores C++ permiten este tipo de sentencias por razones de tipo histoacuterico parece que tal permisividad tiende a ser deprecated (a extinguir) de forma que las uacuteltimas revisiones de algunos compiladores pueden lanzar una advertencia o error en tales circunstancias La forma canoacutenica de definir este tipo de cadenas seriacutea

const char str[] = AEIOU

La expresioacuten secth define una matriz de seis caracteres constantes (almacenado en alguacuten sitio) que no tiene identificador simple (nombre) Tambieacuten define un puntero str al primer elemento de la matriz (maacutes formalmente es un puntero a caraacutecter) Por tanto a falta de un nombre la matriz tiene que ser accedida a traveacutes del puntero (que tendraacute que ser tratado como tal -puntero-) Sin embargo las expresiones

char arr[] = AEIOU sectjchar arr[6] = AEIOUchar arr[6] = AEIOU0char arr[6] = AEIOUchar arr[6] = AEIOU0

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 (secth ) str es un puntero un objeto que puede ser usado con el aacutelgebra de punteros Por ejemplo es vaacutelida la expresioacuten str++ que

equivale a str = str+1 En los otros cinco casos (sectj ) arr es un nemoacutenico que representa una matriz y la expresioacuten arr++ que equivale a arr = arr+1 es ilegal El operando arr+1 es tratado como (amparr[0])+1 lo que es correcto (a un puntero se le puede sumar un entero) La asignacioacuten no seriacutea correcta porque intentariacutea asignar el puntero amparr[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 asignacioacuten 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 asignacioacuten del tipo x = aeiou Si tiene en cambio poderosas funciones en su Libreriacutea Estaacutendar para hacer todo tipo de manipulaciones con cadenas alfanumeacutericas

Es tambieacuten importante distinguir otra diferencia entre las expresiones

char a1[6] = AEIOU0 p1 = ampa1[0]char a2 = AEIOU

Ambas producen matrices de caracteres absolutamente ideacutenticos en contenido y tamantildeo pero a1 es una matriz por lo que sus elementos podriacutean ser alterados usando el identificador Por ejemplo es vaacutelido a1[1]= e o su equivalente (p1+1)=e En cambio un intento anaacutelogo sobre el segundo obliga a usar necesariamente la versioacuten con puntero (a2+1)=e Ademaacutes de que por las razones ya expuestas [2] el resultado no estaacute 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 todaviacutea la asignacioacuten

a2 = aeiou

En este caso el compilador almacena en alguacuten sitio la cadena aeiou0 y asigna a a2 la direccioacuten 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 ninguacuten modo aunque sigue malgastando espacio de memoria

Tambieacuten es posible declarar cadenas de caracteres anchos con el prefijo L como en el ejemplo

wchar_t wptr = Laeiou

en este caso wptr sentildeala una cadena de caracteres anchos ( 221a1) la cadena es del tipo const wchar_t

Para saber la longitud de una constante literal es necesario que el programa repase la cadena hasta encontrar el caraacutecter de fin de cadena lo que se consigue con la funcioacuten de libreriacutea strlen (incluida en la cabecera estaacutendar ltstringhgt) que proporciona la longitud sin contar el caraacutecter final

sect6 Concatenacioacuten de cadenas

Las cadenas literales adyacentes separadas solo por un especio son automaacuteticamente

concatenadas durante la fase de preprocesado ( 141) de la compilacioacuten Por ejemplo Hola mundo es equivalente a Hola mundo Tambieacuten puede usarse la barra invertida ( ) como siacutembolo de continuacioacuten para extender una cadena literal maacutes allaacute del liacutemite de una liacutenea

puts(En realidad esto es una cadena de una linea)char p = Esto es en otra cadena tambieacuten de una sola liacutenea

La concatenacioacuten suprime el caraacutecter nulo de final en las cadenas intermedias y mantiene el de la uacuteltima Esta operacioacuten no altera el significado de los caracteres que intervienen en las cadenas concatenadas Por ejemplo la concatenacioacuten

xA B

Produce la cadena

xAB

que tiene tres caracteres el hexadecimal xA el caraacutecter B y el caracter final nulo 0 En vez del caraacutecter hexadecimal xAB

La concatenacioacuten de cadenas anchas y estrechas tiene resultados impredecibles

323g Constantes de enumeracioacuten

sect1 Sinopsis

Existe un tipo especial de variables denominadas variables enumeradas o

simplemente enumeraciones ( 48 ) Se caracterizan por poder adoptar valores entre una seleccioacuten de constantes enteras denominadas enumeradores cuyos valores son establecidos en el momento de la declaracioacuten del nuevo tipo Como se ha sentildealado son enteros y (una vez establecidos) de valor constante razoacuten por la que se los denomina tambieacuten constantes de enumeracioacuten

Ejemplo

enum estado MALO =0 REGULAR =1 BUENO =2 EXTRA =3

La sentencia anterior declara estado como un tipo de variable de enumeracioacuten Los miembros de esta clase pueden adoptar los valores indicados y son representados por los nemoacutenicos MALO REGULAR BUENO y EXTRA Estas cuatro constantes son los enumeradores del nuevo tipo

Como advertencia a lo indicado hasta aquiacute no confundir la enumeracioacuten (la variable) con los enumeradores (las constantes enteras que delimitan el conjunto de valores posibles de la variable) Tambieacuten 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 = EXTRAestado tu_estado = REGULAR stdcout ltlt Mi estado actual es ltlt mi_estado ltlt endl -gt Mi estado actual es 3

En el caso anterior estado es una enumeracioacuten (tipo geneacuterico) 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 (geneacuterico) con un tipo enum concreto una instancia (variable enumerada) de ese tipo ni con los valores concretos (constantes de enumeracioacuten) que puede adoptar

Para facilitar la legibilidad los identificadores de las constantes de enumeracioacuten son nemoacutenicos y sus nombres suelen estar en mayuacutesculas debido a una larga tradicioacuten CC++ de representar de este modo las constantes

Ya hemos sentildealado que estas constantes (enumeradores) son de tipo entero por lo que pueden ser utilizadas en cualquier expresioacuten donde sean permitidas las constantes enteras Sus identificadores deben ser uacutenicos dentro del aacutembito de la declaracioacuten enum Se permiten inicializadores negativos los valores que adoptan los enumeradores suelen ser uacutenicos (aunque se permiten duplicidades) Para una visioacuten maacutes detallada de las declaraciones de estas constantes

ver enumeraciones ( 48 ) y la explicacioacuten que sigue sobre la palabra clave enum

sect2 Sintaxis

enum [ltnombre-de-tipogt] ltnombr-constgt [= ltvalorgt] [lista_var]

Puede omitirse la palabra clave enum siempre que el nemoacutenico ltnombre-de-tipogt no sea empleado para nada maacutes en el mismo aacutembito Ejemplo

calidad BUENA REGULAR MALA

En este caso el compilador presupone que calidad es un enumerador y no debe existir otra

definicioacuten en el mismo aacutembito de nombres En otras palabras calidad no debe utilizarse en el mismo aacutembito para designar otro objeto

ltnombre-de-tipogt es una etiqueta opcional que identifica al conjunto Puede omitirse si no se va a usar ninguna otra variable de este tipo de enumeracioacuten Ejemplo

enum CIERTO DUDOSO FALSO

ltnombr-constgt es el nombre de la constante de enumeracioacuten (enumerador) a la que opcionalmente puede asignarse el valor definido porltvalorgt En el ejemplo anterior son tres CIERTO DUDOSO y FALSO

ltvalorgt debe ser un entero (ya se ha sentildealado que los enumeradores son constantes

enteras) Si no se especifica ninguacuten valor se supone que es ltpreviogt + 1 donde ltpreviogt es el valor del enumerador anterior de la lista (el valor por defecto para el primero es cero) ltvalorgtpuede ser cualquier expresioacuten que resulte en un entero positivo o negativo (despueacutes de posible conversioacuten a entero)

ltlista_vargt 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 enumeracioacuten de nombre geneacuterico calidad las variables de este tipo pueden adoptar tres valores 0 1 y 2 identificados respectivamente por los nemoacutenicos BUENO REGULAR y MALO ademaacutes se definen dos variables del nuevo

tipo nota yestado

enum calidad BUENO REGULAR MALO nota estado

sect3 Descripcioacuten

La palabra clave enum define una enumeracioacuten 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 nemoacutenicos Por ejemplo la declaracioacuten

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 nemoacutenicos DOM LUNSAB Ademaacutes 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 nemoacutenicos ULT BW40 C40 BW80 C80 y MONO

Los valores asignados a los enumeradores dependen del formato de la declaracioacuten 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 Ademaacutes como puede comprobarse las expresiones de inicializacioacuten pueden incluir enumeradores previamente declarados

Los valores de los enumeradores no tienen porqueacute ser uacutenicos como en el ejemplo que sigue

enum estado BUENO MALO = 1 REGULAR = 1

326 Puntuadores

sect1 Sinopsis

Los signos de puntuacioacuten del lenguaje C++ juegan el mismo papel que sus homoacutenimos en el lenguaje natural escrito Conocidos tambieacuten comopuntuadores [1] son los que se citan a continuacioacuten La mayoriacutea de ellos tienen un doble uso y en ocasiones funcionan tambieacuten

comooperadores ( 49)

[ ] ( ) = ^ amp ndash + | ~ lt gt

sect2 Corchetes [ ]

Los corchetes indican subiacutendices de matrices uni y multi dimensionales

char ch str[] = Cadena de caracteresint mat[3][4] Matriz de 3 x 4ch = str[3] cuarto elemento

sect3 Pareacutentesis ( )

Los pareacutentesis sirven para agrupar expresiones alterar la precedencia normal de los operadores y su asociatividad aislar expresiones condicionales indicar llamadas a funciones y sentildealar los paraacutemetros de estas La sintaxis de C++ exige indefectiblemente el uso de pareacutentesis en muacuteltiples ocasiones En los ejemplos que siguen se muestran algunos usos

d = c (a + b) modifica la precedencia normalif (d == z) ++x imprescindible en la sentencia iffor (x =1 xlt10 x++) imprescindible en la sentencia forfunc() sentildeala llamada a funcioacutenint func() declara funcioacutenint (fptr)() declara puntero a funcioacutenfptr = func asigna valor al puntero

Observe que en el uacuteltimo caso la ausencia de pareacutentesis equivale a ampfunc ( 424a )

Se recomienda el uso de pareacutentesis en las macro-definiciones para evitar problemas potenciales en la expansioacuten Por ejemplo

define CUBO(x) ((x) (x) (x))

sect4 Llaves

Los pares de llaves sentildealan el comienzo y final de una sentencia compuesta es decir bloques de coacutedigo (grupos de sentencias que son tratadas como una unidad) Constituyen el segundo paso (despueacutes de las sentencias) en la estructuracioacuten y compartimentacioacuten del coacutedigo C++

if (d == z) ++x func()

Un bloque es una sentencia compuesta se trata de una sucesioacuten (que puede estar vaciacutea) de sentencias delimitadas por un par de corchetes Desde el punto de vista sintaacutectico un bloque puede ser considerado como una sola sentencia Juega un papel importante en el aacutembito (scope) de los identificadores puesto que un identificador declarado dentro de un bloque tiene un aacutembito

que comienza en el punto de la declaracioacuten 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)

Despueacutes del corchete de cierre no se necesita el punto y coma de fin de sentencia

if (statement) punto y coma ilegal else

Nota las llaves sirven tambieacuten en C++ para otros usos distintos de la pura delimitacioacuten de bloques de coacutedigo Por ejemplo en la definicioacuten de estructuras uniones y clases en cuyo caso si puede ser necesaria la inclusioacuten del punto y coma despueacutes de la llave de cierre

sect5 Coma

La coma como puntuador se utiliza para separar los elementos en las listas de paraacutemetros de una funcioacuten

void func(int n float f char ch)

La coma se usa tambieacuten como un operador en las expresiones con coma ( 4105) Es posible mezclar los dos usos (separador en lista de paraacutemetros y operador) pero deben usarse pareacutentesis para distinguirlos

sect6 Punto y coma

El punto y coma es el signo de fin de sentencia Cualquier expresioacuten legal C++ terminada por un punto y coma (incluyendo la expresioacuten vaciacutea - un punto y coma aislado-) es interpretado como una

sentencia conocidas como sentencia-expresioacuten ( 410) La expresioacuten se evaluacutea y el resultado se descarta si no tiene efectos colaterales C++ la ignora

a + b evaluacutea a + b descarta el resultado++a efecto lateral en a se descarta el valor ++a expresioacuten vaciacutea = sentencia nula

El punto y coma se usa a veces para crear sentencias nulas

for (i = 0 i lt n i++) sentencia nula (hacer nada)

sect7 Dos puntos

Los dos puntos se utilizan para sentildealar sentencias etiquetadas ( 4101)

comienzo x=0 comienzo es la etiquetagoto comienzo

sect8 Puntos suspensivos

Los puntos suspensivos tambieacuten 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 nuacutemero variable de argumentos o pueden ser de tipo variable ( 441) Por ejemplo

void func(int n char ch)

Este prototipo de funcioacuten declara que func estaacute definida de modo que debe ser llamada con al

menos dos argumentos un int y un char Ademaacutes puede tener un cierto nuacutemero de argumentos adicionales (puede omitirse la coma antes de la elipsis)

Se utiliza tambieacuten para indicar que un manejador de excepciones (handler) puede capturar una

excepcioacuten de cualquier tipo ( 162) Ejemplo

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

Nota como podeacuteis ver en ocasiones mi uso particular en los ejemplos de los tres puntos es para indicar cualquier nuacutemero de sentencias Espero que no sea motivo de confusioacuten Desde luego en el caso anterior seriacutea maacutes correcta la notacioacuten

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

sect9 Asterisco

El asterisco puede ser utilizado en C++ de tres formas como una declaracioacuten de tipo de variable

(variable de puntero 42 ) como operador de indireccioacuten (tambieacuten llamado operador

de dereferencia 4911a) y como operador de multiplicacioacuten

Ejemplos

char char_ptr declara puntero a caraacutecterx = int_ptr operador de indireccioacutenl = 2 314 r operador multiplicacioacuten

sect10 Signo igual =

El signo igual = separa la declaracioacuten de variables de las listas de inicializacioacuten

char array[5] = 1 2 3 4 5

Recordemos que al contrario que en C donde las declaraciones no pueden estar precedidas por ninguacuten coacutedigo deben ir al principio en C++ las declaraciones de cualquier tipo pueden aparecer en cualquier punto del coacutedigo (con algunas restricciones)

En la lista de argumentos de una funcioacuten el signo igual indica el valor por defecto para un paraacutemetro

int f(int i = 0) el valor por defecto de k es cero

El signo igual es tambieacuten utilizado como operador de asignacioacuten ( 492) Ejemplo

x = yz += 5

sect11 Almohadilla

Si la almohadilla aparecen en el primer caraacutecter (distinto de espacio en blanco) de una liacutenea

sentildeala directivas de preproceso ( 4910) En este caso es un operador especiacutefico de la fase

de preproceso del coacutedigo fuente Significa una opcioacuten del preprocesador ( 14) que no tiene porqueacute estar asociada necesariamente a generacioacuten de coacutedigo Las directivas se situacutean generalmente al comienzo del programa aunque legalmente pueden aparecer en cualquier punto

Ejemplos de directivas de preproceso

(null directive)define NULO 0include ltstdiohgt

4 Estructura del lenguaje

sect1 Sinopsis

Esta parte proporciona una definicioacuten formal del lenguaje C++ describiendo las formas en que

pueden agruparse correctamente los tokens ( 32) palabras que constituyen el lenguaje entendible por el compilador para formar declaraciones expresiones y otras unidades significativas Para su anaacutelisis lo hemos descompuesto en 13 grupos seguacuten la clasificacioacuten que sigue

sect41 Declaraciones

ObjetosReferencias amp definicionesDefinicioacuten provisionalAacutembitoVisibilidadDuracioacutenUnidad de compilacioacutenEnlazado

Sintaxis de declaraciones

Conversiones aritmeacuteticasInicializacioacutenEspecificadores de clase de almacenamientoModificadores auxiliaresModificadores de funcioacuten

sect42 Punteros

Puntero a objetoDeclaracioacuten de punterosAritmeacutetica de punterosReferenciasPuntero a funcioacuten

sect43 Matrices

Declaracioacuten de matricesMatrices alfanumeacutericasMatrices de punterosMatrices de matrices

sect44 Funciones

DeclaracioacutenDefinicioacutenArgumentos formales y actualesLlamada y conversioacuten de argumentosValores devueltos

sect45 Estructuras

Declaracioacuten de estructurasInicializacioacutenOperaciones permitidasAcceso a miembrosEstructuras y funcionesMatrices de estructurasPunteros a estructurasEstructuras auto-referenciadas

sect46 Campos de Bits

sect47 Uniones

sect48 Enumeraciones

Expresiones

Asociatividad y precedencia de operadoresOrden de evaluacioacutenErrores y desbordamientosExpresiones con coma

sect49 Operadores

AritmeacuteticosAsignacioacutenManejo de BitsOperador ComaCondicionalOp de igualdadOp LoacutegicosModelado de tiposOp de PreprocesoOp de punteroRelacionalessizeoftypeidOp primariosOp antildeadidosOp UnitariosSobrecarga de OperadoresOperador Operador newOperador delete

sect410 Sentencias

Sentencias de etiqueta case defaultSentencias de seleccioacuten if hellip else else if switchSentencias de iteracioacuten while dowhile forSentencias de salto break continue goto return

sect411 Clases

CreacioacutenDeclaracioacutenNombres de ClasesAacutembito de nombresInstanciado de Clasesthis (palabra reservada)Miembros estaacuteticosClases polimoacuterficasFunciones virtualesFunciones dinaacutemicasClases abstractas

sect412 Plantillas

Funciones geneacutericasClases geneacutericas

Aunque las secciones anteriores describen completamente el lenguaje desde una perspectiva formal hemos antildeadido un capiacutetulo adicional (sect413) dedicado a los tecnicismos En eacutel se incluyen algunos consejos y reglas de buena praacutectica para la programacioacuten C++ asiacute como algunos idioms

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

41 Declaraciones

sect1 Sinopsis

Una declaracioacuten es una claacuteusula que introduce nombres en una unidad de compilacioacuten ( 142) o redeclara nombres introducidos por declaraciones previas La norma sentildeala que una declaracioacuten especifica la interpretacioacuten y atributos de estos nombres (como tipo de enlazado y de almacenamiento si es un objeto) asiacute como las condiciones para que una declaracioacuten no sea

tambieacuten una definicioacuten En la paacutegina adjunta se muestra su gramaacutetica ( Gramaacutetica)

Cada una de las introducciones unitarias que puede existir en una declaracioacuten es un declarador (declarator) Asiacute pues un declarador introduce un nombre o redeclara uno

declarado previamente La paacutegina adjunta muestra su gramaacutetica ( Gramaacutetica)

El presente capiacutetulo repasa este importante concepto y otros relacionados tales como objetos clases de almacenamiento tipos aacutembitovisibilidad duracioacuten y enlazado

El aacutembito visibilidad duracioacuten y enlazado son propiedades o caracteriacutesticas 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 definicioacuten de declaracioacuten o la exposicioacuten de su sintaxis

En el epiacutegrafe 4111 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 tambieacuten es dada a conocer mediante una declaracioacuten

411 Entidades

sect1 Presentacioacuten

En relacioacuten con los conceptos que aquiacute nos incumben consideramos que una entidad ( 121) 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 objeto-valor

Un algoritmo con informacioacuten sobre manipulacioacuten de datos Lo denominamos entidad-algoritmo o simplemente algoritmo

Respecto a los objetos-valor una posible clasificacioacuten podriacutea dividirlos en las siguientes categoriacuteas

Agregados

o matrizo estructurao unioacuteno clase unioacuten

Funciones Escalares

o Aritmeacuteticoo Enumeracioacuteno Booleanoo Punteroo Referencia

void

void ( 221) es un tipo especial con un valor muy particular ausencia de valor Los escalares son de caracteriacutesticas tales que su valor no pueden ser descompuestos en partes maacutes pequentildeas

por ejemplo un entero un valor loacutegico (cierto-falso) etc Las funciones ( 44) son principalmente algoritmo ya que estaacuten asociadas a ciertas operaciones (cierta computacioacuten) pero por convencioacuten se les puede asignar un valor es el que devuelven (puede ser void) Por su parte los agregados comparten la caracteriacutestica de que su valor puede ser descompuesto en elementos maacutes simples (escalares)

sect2 El papel de las declaraciones

Haciendo un siacutemil social podriacuteamos decir que las declaraciones son las encargadas de presentar al compilador cualquier entidad que deba existir en el programa Son por tanto el Chambelaacuten de la sociedad C++ Como en el caso de las presentaciones sociales esta presentacioacuten no se reduce a indicar el nombre tambieacuten puede sentildealarse algunas caracteriacutesticas 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

sect3 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 expresioacuten compleja que

represente uniacutevocamente al objeto ( 211 ) Cualquier intento de utilizar una declaracioacuten sin un nombre es un error aunque el nombre no tiene que responder necesariamente a un objeto o funcioacuten Ejemplo

extern int Errorchar Errorchar cptr Ok cptr nombre de punteroclass C Ok C nombre de clasetypedef unsigned int UINT Ok UINT alias para un tipo conocido

Ademaacutes del identificador las declaraciones de funciones pueden incluir ciertos atributos inline ( 4112a) virtual ( 4118a) y explicit ( 4112d1)

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 ( 21 ) Entre otros puede incluir los siguientes char wchar_t bool short int long signed unsigned float double void

Relativos al tipo de almacenamiento Determina el sitio en que se guarda el objeto y su

duracioacuten ( 213 ) 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 disquisicioacuten respecto a si un mismo objeto Por ejemplo una variable puede estar referenciado por dos identificadores distintos (que se refieren a la misma regioacuten de memoria) En la mayoriacutea de lenguajes de programacioacuten esta distincioacuten entre identificador y almacenamiento estaacute perfectamente establecida y suelen proporcionar mecanismos sintaacutecticos para que dos identificadores puedan referirse al mismo almacenamiento

412 Declaraciones y definiciones

sect1 Sinopsis

Utilizando un leacutexico formalista podemos decir que una declaracioacuten es una sentencia que

introduce un nombre en una unidad de compilacioacuten ( 142) daacutendole existencia semaacutentica Esto de la existencia semaacutentica es una forma elegante de decir que a partir de ahiacute el compilador sabe que cosa es (representa) ese nombre La forma de darle existencia semaacutentica a las entidades es declararlos (algo asiacute como presentarlos formalmente en el coacutedigo) Por ejemplo si declaramos una variable x o una funcioacuten func a partir de ahiacute el compilador sabe que x es una variable de tal tipo y que func es una funcioacuten de caracteriacutesticas cuales

El punto importante a resaltar aquiacute es que cada declaracioacuten asocia un nombre con un tipo de dato

lo que en C++ (una sociedad muy clasista 22) es importante ya que el conocimiento del tipo que corresponde a un identificador proporciona al compilador mucha informacioacuten sobre la entidad

representada por este (en muchas ocasiones casi toda la informacioacuten necesaria ) En especial el compilador dispone de una amplia informacioacuten acerca del uso de los tipos baacutesicos que operaciones son permitidas y que significado tienen estas operaciones

No olvidar que una declaracioacuten no hace nada maacutes que esto Es decir no antildeade ninguna otra informacioacuten distinta de relacionar una etiqueta con un tipo Posteriormente cuando esta etiqueta esteacute asociada con una entidad concreta (con una zona de memoria) las operaciones permitidas se

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

Ambas producen matrices de caracteres absolutamente ideacutenticos en contenido y tamantildeo pero a1 es una matriz por lo que sus elementos podriacutean ser alterados usando el identificador Por ejemplo es vaacutelido a1[1]= e o su equivalente (p1+1)=e En cambio un intento anaacutelogo sobre el segundo obliga a usar necesariamente la versioacuten con puntero (a2+1)=e Ademaacutes de que por las razones ya expuestas [2] el resultado no estaacute 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 todaviacutea la asignacioacuten

a2 = aeiou

En este caso el compilador almacena en alguacuten sitio la cadena aeiou0 y asigna a a2 la direccioacuten 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 ninguacuten modo aunque sigue malgastando espacio de memoria

Tambieacuten es posible declarar cadenas de caracteres anchos con el prefijo L como en el ejemplo

wchar_t wptr = Laeiou

en este caso wptr sentildeala una cadena de caracteres anchos ( 221a1) la cadena es del tipo const wchar_t

Para saber la longitud de una constante literal es necesario que el programa repase la cadena hasta encontrar el caraacutecter de fin de cadena lo que se consigue con la funcioacuten de libreriacutea strlen (incluida en la cabecera estaacutendar ltstringhgt) que proporciona la longitud sin contar el caraacutecter final

sect6 Concatenacioacuten de cadenas

Las cadenas literales adyacentes separadas solo por un especio son automaacuteticamente

concatenadas durante la fase de preprocesado ( 141) de la compilacioacuten Por ejemplo Hola mundo es equivalente a Hola mundo Tambieacuten puede usarse la barra invertida ( ) como siacutembolo de continuacioacuten para extender una cadena literal maacutes allaacute del liacutemite de una liacutenea

puts(En realidad esto es una cadena de una linea)char p = Esto es en otra cadena tambieacuten de una sola liacutenea

La concatenacioacuten suprime el caraacutecter nulo de final en las cadenas intermedias y mantiene el de la uacuteltima Esta operacioacuten no altera el significado de los caracteres que intervienen en las cadenas concatenadas Por ejemplo la concatenacioacuten

xA B

Produce la cadena

xAB

que tiene tres caracteres el hexadecimal xA el caraacutecter B y el caracter final nulo 0 En vez del caraacutecter hexadecimal xAB

La concatenacioacuten de cadenas anchas y estrechas tiene resultados impredecibles

323g Constantes de enumeracioacuten

sect1 Sinopsis

Existe un tipo especial de variables denominadas variables enumeradas o

simplemente enumeraciones ( 48 ) Se caracterizan por poder adoptar valores entre una seleccioacuten de constantes enteras denominadas enumeradores cuyos valores son establecidos en el momento de la declaracioacuten del nuevo tipo Como se ha sentildealado son enteros y (una vez establecidos) de valor constante razoacuten por la que se los denomina tambieacuten constantes de enumeracioacuten

Ejemplo

enum estado MALO =0 REGULAR =1 BUENO =2 EXTRA =3

La sentencia anterior declara estado como un tipo de variable de enumeracioacuten Los miembros de esta clase pueden adoptar los valores indicados y son representados por los nemoacutenicos MALO REGULAR BUENO y EXTRA Estas cuatro constantes son los enumeradores del nuevo tipo

Como advertencia a lo indicado hasta aquiacute no confundir la enumeracioacuten (la variable) con los enumeradores (las constantes enteras que delimitan el conjunto de valores posibles de la variable) Tambieacuten 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 = EXTRAestado tu_estado = REGULAR stdcout ltlt Mi estado actual es ltlt mi_estado ltlt endl -gt Mi estado actual es 3

En el caso anterior estado es una enumeracioacuten (tipo geneacuterico) 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 (geneacuterico) con un tipo enum concreto una instancia (variable enumerada) de ese tipo ni con los valores concretos (constantes de enumeracioacuten) que puede adoptar

Para facilitar la legibilidad los identificadores de las constantes de enumeracioacuten son nemoacutenicos y sus nombres suelen estar en mayuacutesculas debido a una larga tradicioacuten CC++ de representar de este modo las constantes

Ya hemos sentildealado que estas constantes (enumeradores) son de tipo entero por lo que pueden ser utilizadas en cualquier expresioacuten donde sean permitidas las constantes enteras Sus identificadores deben ser uacutenicos dentro del aacutembito de la declaracioacuten enum Se permiten inicializadores negativos los valores que adoptan los enumeradores suelen ser uacutenicos (aunque se permiten duplicidades) Para una visioacuten maacutes detallada de las declaraciones de estas constantes

ver enumeraciones ( 48 ) y la explicacioacuten que sigue sobre la palabra clave enum

sect2 Sintaxis

enum [ltnombre-de-tipogt] ltnombr-constgt [= ltvalorgt] [lista_var]

Puede omitirse la palabra clave enum siempre que el nemoacutenico ltnombre-de-tipogt no sea empleado para nada maacutes en el mismo aacutembito Ejemplo

calidad BUENA REGULAR MALA

En este caso el compilador presupone que calidad es un enumerador y no debe existir otra

definicioacuten en el mismo aacutembito de nombres En otras palabras calidad no debe utilizarse en el mismo aacutembito para designar otro objeto

ltnombre-de-tipogt es una etiqueta opcional que identifica al conjunto Puede omitirse si no se va a usar ninguna otra variable de este tipo de enumeracioacuten Ejemplo

enum CIERTO DUDOSO FALSO

ltnombr-constgt es el nombre de la constante de enumeracioacuten (enumerador) a la que opcionalmente puede asignarse el valor definido porltvalorgt En el ejemplo anterior son tres CIERTO DUDOSO y FALSO

ltvalorgt debe ser un entero (ya se ha sentildealado que los enumeradores son constantes

enteras) Si no se especifica ninguacuten valor se supone que es ltpreviogt + 1 donde ltpreviogt es el valor del enumerador anterior de la lista (el valor por defecto para el primero es cero) ltvalorgtpuede ser cualquier expresioacuten que resulte en un entero positivo o negativo (despueacutes de posible conversioacuten a entero)

ltlista_vargt 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 enumeracioacuten de nombre geneacuterico calidad las variables de este tipo pueden adoptar tres valores 0 1 y 2 identificados respectivamente por los nemoacutenicos BUENO REGULAR y MALO ademaacutes se definen dos variables del nuevo

tipo nota yestado

enum calidad BUENO REGULAR MALO nota estado

sect3 Descripcioacuten

La palabra clave enum define una enumeracioacuten 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 nemoacutenicos Por ejemplo la declaracioacuten

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 nemoacutenicos DOM LUNSAB Ademaacutes 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 nemoacutenicos ULT BW40 C40 BW80 C80 y MONO

Los valores asignados a los enumeradores dependen del formato de la declaracioacuten 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 Ademaacutes como puede comprobarse las expresiones de inicializacioacuten pueden incluir enumeradores previamente declarados

Los valores de los enumeradores no tienen porqueacute ser uacutenicos como en el ejemplo que sigue

enum estado BUENO MALO = 1 REGULAR = 1

326 Puntuadores

sect1 Sinopsis

Los signos de puntuacioacuten del lenguaje C++ juegan el mismo papel que sus homoacutenimos en el lenguaje natural escrito Conocidos tambieacuten comopuntuadores [1] son los que se citan a continuacioacuten La mayoriacutea de ellos tienen un doble uso y en ocasiones funcionan tambieacuten

comooperadores ( 49)

[ ] ( ) = ^ amp ndash + | ~ lt gt

sect2 Corchetes [ ]

Los corchetes indican subiacutendices de matrices uni y multi dimensionales

char ch str[] = Cadena de caracteresint mat[3][4] Matriz de 3 x 4ch = str[3] cuarto elemento

sect3 Pareacutentesis ( )

Los pareacutentesis sirven para agrupar expresiones alterar la precedencia normal de los operadores y su asociatividad aislar expresiones condicionales indicar llamadas a funciones y sentildealar los paraacutemetros de estas La sintaxis de C++ exige indefectiblemente el uso de pareacutentesis en muacuteltiples ocasiones En los ejemplos que siguen se muestran algunos usos

d = c (a + b) modifica la precedencia normalif (d == z) ++x imprescindible en la sentencia iffor (x =1 xlt10 x++) imprescindible en la sentencia forfunc() sentildeala llamada a funcioacutenint func() declara funcioacutenint (fptr)() declara puntero a funcioacutenfptr = func asigna valor al puntero

Observe que en el uacuteltimo caso la ausencia de pareacutentesis equivale a ampfunc ( 424a )

Se recomienda el uso de pareacutentesis en las macro-definiciones para evitar problemas potenciales en la expansioacuten Por ejemplo

define CUBO(x) ((x) (x) (x))

sect4 Llaves

Los pares de llaves sentildealan el comienzo y final de una sentencia compuesta es decir bloques de coacutedigo (grupos de sentencias que son tratadas como una unidad) Constituyen el segundo paso (despueacutes de las sentencias) en la estructuracioacuten y compartimentacioacuten del coacutedigo C++

if (d == z) ++x func()

Un bloque es una sentencia compuesta se trata de una sucesioacuten (que puede estar vaciacutea) de sentencias delimitadas por un par de corchetes Desde el punto de vista sintaacutectico un bloque puede ser considerado como una sola sentencia Juega un papel importante en el aacutembito (scope) de los identificadores puesto que un identificador declarado dentro de un bloque tiene un aacutembito

que comienza en el punto de la declaracioacuten 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)

Despueacutes del corchete de cierre no se necesita el punto y coma de fin de sentencia

if (statement) punto y coma ilegal else

Nota las llaves sirven tambieacuten en C++ para otros usos distintos de la pura delimitacioacuten de bloques de coacutedigo Por ejemplo en la definicioacuten de estructuras uniones y clases en cuyo caso si puede ser necesaria la inclusioacuten del punto y coma despueacutes de la llave de cierre

sect5 Coma

La coma como puntuador se utiliza para separar los elementos en las listas de paraacutemetros de una funcioacuten

void func(int n float f char ch)

La coma se usa tambieacuten como un operador en las expresiones con coma ( 4105) Es posible mezclar los dos usos (separador en lista de paraacutemetros y operador) pero deben usarse pareacutentesis para distinguirlos

sect6 Punto y coma

El punto y coma es el signo de fin de sentencia Cualquier expresioacuten legal C++ terminada por un punto y coma (incluyendo la expresioacuten vaciacutea - un punto y coma aislado-) es interpretado como una

sentencia conocidas como sentencia-expresioacuten ( 410) La expresioacuten se evaluacutea y el resultado se descarta si no tiene efectos colaterales C++ la ignora

a + b evaluacutea a + b descarta el resultado++a efecto lateral en a se descarta el valor ++a expresioacuten vaciacutea = sentencia nula

El punto y coma se usa a veces para crear sentencias nulas

for (i = 0 i lt n i++) sentencia nula (hacer nada)

sect7 Dos puntos

Los dos puntos se utilizan para sentildealar sentencias etiquetadas ( 4101)

comienzo x=0 comienzo es la etiquetagoto comienzo

sect8 Puntos suspensivos

Los puntos suspensivos tambieacuten 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 nuacutemero variable de argumentos o pueden ser de tipo variable ( 441) Por ejemplo

void func(int n char ch)

Este prototipo de funcioacuten declara que func estaacute definida de modo que debe ser llamada con al

menos dos argumentos un int y un char Ademaacutes puede tener un cierto nuacutemero de argumentos adicionales (puede omitirse la coma antes de la elipsis)

Se utiliza tambieacuten para indicar que un manejador de excepciones (handler) puede capturar una

excepcioacuten de cualquier tipo ( 162) Ejemplo

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

Nota como podeacuteis ver en ocasiones mi uso particular en los ejemplos de los tres puntos es para indicar cualquier nuacutemero de sentencias Espero que no sea motivo de confusioacuten Desde luego en el caso anterior seriacutea maacutes correcta la notacioacuten

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

sect9 Asterisco

El asterisco puede ser utilizado en C++ de tres formas como una declaracioacuten de tipo de variable

(variable de puntero 42 ) como operador de indireccioacuten (tambieacuten llamado operador

de dereferencia 4911a) y como operador de multiplicacioacuten

Ejemplos

char char_ptr declara puntero a caraacutecterx = int_ptr operador de indireccioacutenl = 2 314 r operador multiplicacioacuten

sect10 Signo igual =

El signo igual = separa la declaracioacuten de variables de las listas de inicializacioacuten

char array[5] = 1 2 3 4 5

Recordemos que al contrario que en C donde las declaraciones no pueden estar precedidas por ninguacuten coacutedigo deben ir al principio en C++ las declaraciones de cualquier tipo pueden aparecer en cualquier punto del coacutedigo (con algunas restricciones)

En la lista de argumentos de una funcioacuten el signo igual indica el valor por defecto para un paraacutemetro

int f(int i = 0) el valor por defecto de k es cero

El signo igual es tambieacuten utilizado como operador de asignacioacuten ( 492) Ejemplo

x = yz += 5

sect11 Almohadilla

Si la almohadilla aparecen en el primer caraacutecter (distinto de espacio en blanco) de una liacutenea

sentildeala directivas de preproceso ( 4910) En este caso es un operador especiacutefico de la fase

de preproceso del coacutedigo fuente Significa una opcioacuten del preprocesador ( 14) que no tiene porqueacute estar asociada necesariamente a generacioacuten de coacutedigo Las directivas se situacutean generalmente al comienzo del programa aunque legalmente pueden aparecer en cualquier punto

Ejemplos de directivas de preproceso

(null directive)define NULO 0include ltstdiohgt

4 Estructura del lenguaje

sect1 Sinopsis

Esta parte proporciona una definicioacuten formal del lenguaje C++ describiendo las formas en que

pueden agruparse correctamente los tokens ( 32) palabras que constituyen el lenguaje entendible por el compilador para formar declaraciones expresiones y otras unidades significativas Para su anaacutelisis lo hemos descompuesto en 13 grupos seguacuten la clasificacioacuten que sigue

sect41 Declaraciones

ObjetosReferencias amp definicionesDefinicioacuten provisionalAacutembitoVisibilidadDuracioacutenUnidad de compilacioacutenEnlazado

Sintaxis de declaraciones

Conversiones aritmeacuteticasInicializacioacutenEspecificadores de clase de almacenamientoModificadores auxiliaresModificadores de funcioacuten

sect42 Punteros

Puntero a objetoDeclaracioacuten de punterosAritmeacutetica de punterosReferenciasPuntero a funcioacuten

sect43 Matrices

Declaracioacuten de matricesMatrices alfanumeacutericasMatrices de punterosMatrices de matrices

sect44 Funciones

DeclaracioacutenDefinicioacutenArgumentos formales y actualesLlamada y conversioacuten de argumentosValores devueltos

sect45 Estructuras

Declaracioacuten de estructurasInicializacioacutenOperaciones permitidasAcceso a miembrosEstructuras y funcionesMatrices de estructurasPunteros a estructurasEstructuras auto-referenciadas

sect46 Campos de Bits

sect47 Uniones

sect48 Enumeraciones

Expresiones

Asociatividad y precedencia de operadoresOrden de evaluacioacutenErrores y desbordamientosExpresiones con coma

sect49 Operadores

AritmeacuteticosAsignacioacutenManejo de BitsOperador ComaCondicionalOp de igualdadOp LoacutegicosModelado de tiposOp de PreprocesoOp de punteroRelacionalessizeoftypeidOp primariosOp antildeadidosOp UnitariosSobrecarga de OperadoresOperador Operador newOperador delete

sect410 Sentencias

Sentencias de etiqueta case defaultSentencias de seleccioacuten if hellip else else if switchSentencias de iteracioacuten while dowhile forSentencias de salto break continue goto return

sect411 Clases

CreacioacutenDeclaracioacutenNombres de ClasesAacutembito de nombresInstanciado de Clasesthis (palabra reservada)Miembros estaacuteticosClases polimoacuterficasFunciones virtualesFunciones dinaacutemicasClases abstractas

sect412 Plantillas

Funciones geneacutericasClases geneacutericas

Aunque las secciones anteriores describen completamente el lenguaje desde una perspectiva formal hemos antildeadido un capiacutetulo adicional (sect413) dedicado a los tecnicismos En eacutel se incluyen algunos consejos y reglas de buena praacutectica para la programacioacuten C++ asiacute como algunos idioms

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

41 Declaraciones

sect1 Sinopsis

Una declaracioacuten es una claacuteusula que introduce nombres en una unidad de compilacioacuten ( 142) o redeclara nombres introducidos por declaraciones previas La norma sentildeala que una declaracioacuten especifica la interpretacioacuten y atributos de estos nombres (como tipo de enlazado y de almacenamiento si es un objeto) asiacute como las condiciones para que una declaracioacuten no sea

tambieacuten una definicioacuten En la paacutegina adjunta se muestra su gramaacutetica ( Gramaacutetica)

Cada una de las introducciones unitarias que puede existir en una declaracioacuten es un declarador (declarator) Asiacute pues un declarador introduce un nombre o redeclara uno

declarado previamente La paacutegina adjunta muestra su gramaacutetica ( Gramaacutetica)

El presente capiacutetulo repasa este importante concepto y otros relacionados tales como objetos clases de almacenamiento tipos aacutembitovisibilidad duracioacuten y enlazado

El aacutembito visibilidad duracioacuten y enlazado son propiedades o caracteriacutesticas 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 definicioacuten de declaracioacuten o la exposicioacuten de su sintaxis

En el epiacutegrafe 4111 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 tambieacuten es dada a conocer mediante una declaracioacuten

411 Entidades

sect1 Presentacioacuten

En relacioacuten con los conceptos que aquiacute nos incumben consideramos que una entidad ( 121) 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 objeto-valor

Un algoritmo con informacioacuten sobre manipulacioacuten de datos Lo denominamos entidad-algoritmo o simplemente algoritmo

Respecto a los objetos-valor una posible clasificacioacuten podriacutea dividirlos en las siguientes categoriacuteas

Agregados

o matrizo estructurao unioacuteno clase unioacuten

Funciones Escalares

o Aritmeacuteticoo Enumeracioacuteno Booleanoo Punteroo Referencia

void

void ( 221) es un tipo especial con un valor muy particular ausencia de valor Los escalares son de caracteriacutesticas tales que su valor no pueden ser descompuestos en partes maacutes pequentildeas

por ejemplo un entero un valor loacutegico (cierto-falso) etc Las funciones ( 44) son principalmente algoritmo ya que estaacuten asociadas a ciertas operaciones (cierta computacioacuten) pero por convencioacuten se les puede asignar un valor es el que devuelven (puede ser void) Por su parte los agregados comparten la caracteriacutestica de que su valor puede ser descompuesto en elementos maacutes simples (escalares)

sect2 El papel de las declaraciones

Haciendo un siacutemil social podriacuteamos decir que las declaraciones son las encargadas de presentar al compilador cualquier entidad que deba existir en el programa Son por tanto el Chambelaacuten de la sociedad C++ Como en el caso de las presentaciones sociales esta presentacioacuten no se reduce a indicar el nombre tambieacuten puede sentildealarse algunas caracteriacutesticas 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

sect3 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 expresioacuten compleja que

represente uniacutevocamente al objeto ( 211 ) Cualquier intento de utilizar una declaracioacuten sin un nombre es un error aunque el nombre no tiene que responder necesariamente a un objeto o funcioacuten Ejemplo

extern int Errorchar Errorchar cptr Ok cptr nombre de punteroclass C Ok C nombre de clasetypedef unsigned int UINT Ok UINT alias para un tipo conocido

Ademaacutes del identificador las declaraciones de funciones pueden incluir ciertos atributos inline ( 4112a) virtual ( 4118a) y explicit ( 4112d1)

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 ( 21 ) Entre otros puede incluir los siguientes char wchar_t bool short int long signed unsigned float double void

Relativos al tipo de almacenamiento Determina el sitio en que se guarda el objeto y su

duracioacuten ( 213 ) 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 disquisicioacuten respecto a si un mismo objeto Por ejemplo una variable puede estar referenciado por dos identificadores distintos (que se refieren a la misma regioacuten de memoria) En la mayoriacutea de lenguajes de programacioacuten esta distincioacuten entre identificador y almacenamiento estaacute perfectamente establecida y suelen proporcionar mecanismos sintaacutecticos para que dos identificadores puedan referirse al mismo almacenamiento

412 Declaraciones y definiciones

sect1 Sinopsis

Utilizando un leacutexico formalista podemos decir que una declaracioacuten es una sentencia que

introduce un nombre en una unidad de compilacioacuten ( 142) daacutendole existencia semaacutentica Esto de la existencia semaacutentica es una forma elegante de decir que a partir de ahiacute el compilador sabe que cosa es (representa) ese nombre La forma de darle existencia semaacutentica a las entidades es declararlos (algo asiacute como presentarlos formalmente en el coacutedigo) Por ejemplo si declaramos una variable x o una funcioacuten func a partir de ahiacute el compilador sabe que x es una variable de tal tipo y que func es una funcioacuten de caracteriacutesticas cuales

El punto importante a resaltar aquiacute es que cada declaracioacuten asocia un nombre con un tipo de dato

lo que en C++ (una sociedad muy clasista 22) es importante ya que el conocimiento del tipo que corresponde a un identificador proporciona al compilador mucha informacioacuten sobre la entidad

representada por este (en muchas ocasiones casi toda la informacioacuten necesaria ) En especial el compilador dispone de una amplia informacioacuten acerca del uso de los tipos baacutesicos que operaciones son permitidas y que significado tienen estas operaciones

No olvidar que una declaracioacuten no hace nada maacutes que esto Es decir no antildeade ninguna otra informacioacuten distinta de relacionar una etiqueta con un tipo Posteriormente cuando esta etiqueta esteacute asociada con una entidad concreta (con una zona de memoria) las operaciones permitidas se

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

que tiene tres caracteres el hexadecimal xA el caraacutecter B y el caracter final nulo 0 En vez del caraacutecter hexadecimal xAB

La concatenacioacuten de cadenas anchas y estrechas tiene resultados impredecibles

323g Constantes de enumeracioacuten

sect1 Sinopsis

Existe un tipo especial de variables denominadas variables enumeradas o

simplemente enumeraciones ( 48 ) Se caracterizan por poder adoptar valores entre una seleccioacuten de constantes enteras denominadas enumeradores cuyos valores son establecidos en el momento de la declaracioacuten del nuevo tipo Como se ha sentildealado son enteros y (una vez establecidos) de valor constante razoacuten por la que se los denomina tambieacuten constantes de enumeracioacuten

Ejemplo

enum estado MALO =0 REGULAR =1 BUENO =2 EXTRA =3

La sentencia anterior declara estado como un tipo de variable de enumeracioacuten Los miembros de esta clase pueden adoptar los valores indicados y son representados por los nemoacutenicos MALO REGULAR BUENO y EXTRA Estas cuatro constantes son los enumeradores del nuevo tipo

Como advertencia a lo indicado hasta aquiacute no confundir la enumeracioacuten (la variable) con los enumeradores (las constantes enteras que delimitan el conjunto de valores posibles de la variable) Tambieacuten 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 = EXTRAestado tu_estado = REGULAR stdcout ltlt Mi estado actual es ltlt mi_estado ltlt endl -gt Mi estado actual es 3

En el caso anterior estado es una enumeracioacuten (tipo geneacuterico) 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 (geneacuterico) con un tipo enum concreto una instancia (variable enumerada) de ese tipo ni con los valores concretos (constantes de enumeracioacuten) que puede adoptar

Para facilitar la legibilidad los identificadores de las constantes de enumeracioacuten son nemoacutenicos y sus nombres suelen estar en mayuacutesculas debido a una larga tradicioacuten CC++ de representar de este modo las constantes

Ya hemos sentildealado que estas constantes (enumeradores) son de tipo entero por lo que pueden ser utilizadas en cualquier expresioacuten donde sean permitidas las constantes enteras Sus identificadores deben ser uacutenicos dentro del aacutembito de la declaracioacuten enum Se permiten inicializadores negativos los valores que adoptan los enumeradores suelen ser uacutenicos (aunque se permiten duplicidades) Para una visioacuten maacutes detallada de las declaraciones de estas constantes

ver enumeraciones ( 48 ) y la explicacioacuten que sigue sobre la palabra clave enum

sect2 Sintaxis

enum [ltnombre-de-tipogt] ltnombr-constgt [= ltvalorgt] [lista_var]

Puede omitirse la palabra clave enum siempre que el nemoacutenico ltnombre-de-tipogt no sea empleado para nada maacutes en el mismo aacutembito Ejemplo

calidad BUENA REGULAR MALA

En este caso el compilador presupone que calidad es un enumerador y no debe existir otra

definicioacuten en el mismo aacutembito de nombres En otras palabras calidad no debe utilizarse en el mismo aacutembito para designar otro objeto

ltnombre-de-tipogt es una etiqueta opcional que identifica al conjunto Puede omitirse si no se va a usar ninguna otra variable de este tipo de enumeracioacuten Ejemplo

enum CIERTO DUDOSO FALSO

ltnombr-constgt es el nombre de la constante de enumeracioacuten (enumerador) a la que opcionalmente puede asignarse el valor definido porltvalorgt En el ejemplo anterior son tres CIERTO DUDOSO y FALSO

ltvalorgt debe ser un entero (ya se ha sentildealado que los enumeradores son constantes

enteras) Si no se especifica ninguacuten valor se supone que es ltpreviogt + 1 donde ltpreviogt es el valor del enumerador anterior de la lista (el valor por defecto para el primero es cero) ltvalorgtpuede ser cualquier expresioacuten que resulte en un entero positivo o negativo (despueacutes de posible conversioacuten a entero)

ltlista_vargt 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 enumeracioacuten de nombre geneacuterico calidad las variables de este tipo pueden adoptar tres valores 0 1 y 2 identificados respectivamente por los nemoacutenicos BUENO REGULAR y MALO ademaacutes se definen dos variables del nuevo

tipo nota yestado

enum calidad BUENO REGULAR MALO nota estado

sect3 Descripcioacuten

La palabra clave enum define una enumeracioacuten 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 nemoacutenicos Por ejemplo la declaracioacuten

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 nemoacutenicos DOM LUNSAB Ademaacutes 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 nemoacutenicos ULT BW40 C40 BW80 C80 y MONO

Los valores asignados a los enumeradores dependen del formato de la declaracioacuten 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 Ademaacutes como puede comprobarse las expresiones de inicializacioacuten pueden incluir enumeradores previamente declarados

Los valores de los enumeradores no tienen porqueacute ser uacutenicos como en el ejemplo que sigue

enum estado BUENO MALO = 1 REGULAR = 1

326 Puntuadores

sect1 Sinopsis

Los signos de puntuacioacuten del lenguaje C++ juegan el mismo papel que sus homoacutenimos en el lenguaje natural escrito Conocidos tambieacuten comopuntuadores [1] son los que se citan a continuacioacuten La mayoriacutea de ellos tienen un doble uso y en ocasiones funcionan tambieacuten

comooperadores ( 49)

[ ] ( ) = ^ amp ndash + | ~ lt gt

sect2 Corchetes [ ]

Los corchetes indican subiacutendices de matrices uni y multi dimensionales

char ch str[] = Cadena de caracteresint mat[3][4] Matriz de 3 x 4ch = str[3] cuarto elemento

sect3 Pareacutentesis ( )

Los pareacutentesis sirven para agrupar expresiones alterar la precedencia normal de los operadores y su asociatividad aislar expresiones condicionales indicar llamadas a funciones y sentildealar los paraacutemetros de estas La sintaxis de C++ exige indefectiblemente el uso de pareacutentesis en muacuteltiples ocasiones En los ejemplos que siguen se muestran algunos usos

d = c (a + b) modifica la precedencia normalif (d == z) ++x imprescindible en la sentencia iffor (x =1 xlt10 x++) imprescindible en la sentencia forfunc() sentildeala llamada a funcioacutenint func() declara funcioacutenint (fptr)() declara puntero a funcioacutenfptr = func asigna valor al puntero

Observe que en el uacuteltimo caso la ausencia de pareacutentesis equivale a ampfunc ( 424a )

Se recomienda el uso de pareacutentesis en las macro-definiciones para evitar problemas potenciales en la expansioacuten Por ejemplo

define CUBO(x) ((x) (x) (x))

sect4 Llaves

Los pares de llaves sentildealan el comienzo y final de una sentencia compuesta es decir bloques de coacutedigo (grupos de sentencias que son tratadas como una unidad) Constituyen el segundo paso (despueacutes de las sentencias) en la estructuracioacuten y compartimentacioacuten del coacutedigo C++

if (d == z) ++x func()

Un bloque es una sentencia compuesta se trata de una sucesioacuten (que puede estar vaciacutea) de sentencias delimitadas por un par de corchetes Desde el punto de vista sintaacutectico un bloque puede ser considerado como una sola sentencia Juega un papel importante en el aacutembito (scope) de los identificadores puesto que un identificador declarado dentro de un bloque tiene un aacutembito

que comienza en el punto de la declaracioacuten 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)

Despueacutes del corchete de cierre no se necesita el punto y coma de fin de sentencia

if (statement) punto y coma ilegal else

Nota las llaves sirven tambieacuten en C++ para otros usos distintos de la pura delimitacioacuten de bloques de coacutedigo Por ejemplo en la definicioacuten de estructuras uniones y clases en cuyo caso si puede ser necesaria la inclusioacuten del punto y coma despueacutes de la llave de cierre

sect5 Coma

La coma como puntuador se utiliza para separar los elementos en las listas de paraacutemetros de una funcioacuten

void func(int n float f char ch)

La coma se usa tambieacuten como un operador en las expresiones con coma ( 4105) Es posible mezclar los dos usos (separador en lista de paraacutemetros y operador) pero deben usarse pareacutentesis para distinguirlos

sect6 Punto y coma

El punto y coma es el signo de fin de sentencia Cualquier expresioacuten legal C++ terminada por un punto y coma (incluyendo la expresioacuten vaciacutea - un punto y coma aislado-) es interpretado como una

sentencia conocidas como sentencia-expresioacuten ( 410) La expresioacuten se evaluacutea y el resultado se descarta si no tiene efectos colaterales C++ la ignora

a + b evaluacutea a + b descarta el resultado++a efecto lateral en a se descarta el valor ++a expresioacuten vaciacutea = sentencia nula

El punto y coma se usa a veces para crear sentencias nulas

for (i = 0 i lt n i++) sentencia nula (hacer nada)

sect7 Dos puntos

Los dos puntos se utilizan para sentildealar sentencias etiquetadas ( 4101)

comienzo x=0 comienzo es la etiquetagoto comienzo

sect8 Puntos suspensivos

Los puntos suspensivos tambieacuten 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 nuacutemero variable de argumentos o pueden ser de tipo variable ( 441) Por ejemplo

void func(int n char ch)

Este prototipo de funcioacuten declara que func estaacute definida de modo que debe ser llamada con al

menos dos argumentos un int y un char Ademaacutes puede tener un cierto nuacutemero de argumentos adicionales (puede omitirse la coma antes de la elipsis)

Se utiliza tambieacuten para indicar que un manejador de excepciones (handler) puede capturar una

excepcioacuten de cualquier tipo ( 162) Ejemplo

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

Nota como podeacuteis ver en ocasiones mi uso particular en los ejemplos de los tres puntos es para indicar cualquier nuacutemero de sentencias Espero que no sea motivo de confusioacuten Desde luego en el caso anterior seriacutea maacutes correcta la notacioacuten

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

sect9 Asterisco

El asterisco puede ser utilizado en C++ de tres formas como una declaracioacuten de tipo de variable

(variable de puntero 42 ) como operador de indireccioacuten (tambieacuten llamado operador

de dereferencia 4911a) y como operador de multiplicacioacuten

Ejemplos

char char_ptr declara puntero a caraacutecterx = int_ptr operador de indireccioacutenl = 2 314 r operador multiplicacioacuten

sect10 Signo igual =

El signo igual = separa la declaracioacuten de variables de las listas de inicializacioacuten

char array[5] = 1 2 3 4 5

Recordemos que al contrario que en C donde las declaraciones no pueden estar precedidas por ninguacuten coacutedigo deben ir al principio en C++ las declaraciones de cualquier tipo pueden aparecer en cualquier punto del coacutedigo (con algunas restricciones)

En la lista de argumentos de una funcioacuten el signo igual indica el valor por defecto para un paraacutemetro

int f(int i = 0) el valor por defecto de k es cero

El signo igual es tambieacuten utilizado como operador de asignacioacuten ( 492) Ejemplo

x = yz += 5

sect11 Almohadilla

Si la almohadilla aparecen en el primer caraacutecter (distinto de espacio en blanco) de una liacutenea

sentildeala directivas de preproceso ( 4910) En este caso es un operador especiacutefico de la fase

de preproceso del coacutedigo fuente Significa una opcioacuten del preprocesador ( 14) que no tiene porqueacute estar asociada necesariamente a generacioacuten de coacutedigo Las directivas se situacutean generalmente al comienzo del programa aunque legalmente pueden aparecer en cualquier punto

Ejemplos de directivas de preproceso

(null directive)define NULO 0include ltstdiohgt

4 Estructura del lenguaje

sect1 Sinopsis

Esta parte proporciona una definicioacuten formal del lenguaje C++ describiendo las formas en que

pueden agruparse correctamente los tokens ( 32) palabras que constituyen el lenguaje entendible por el compilador para formar declaraciones expresiones y otras unidades significativas Para su anaacutelisis lo hemos descompuesto en 13 grupos seguacuten la clasificacioacuten que sigue

sect41 Declaraciones

ObjetosReferencias amp definicionesDefinicioacuten provisionalAacutembitoVisibilidadDuracioacutenUnidad de compilacioacutenEnlazado

Sintaxis de declaraciones

Conversiones aritmeacuteticasInicializacioacutenEspecificadores de clase de almacenamientoModificadores auxiliaresModificadores de funcioacuten

sect42 Punteros

Puntero a objetoDeclaracioacuten de punterosAritmeacutetica de punterosReferenciasPuntero a funcioacuten

sect43 Matrices

Declaracioacuten de matricesMatrices alfanumeacutericasMatrices de punterosMatrices de matrices

sect44 Funciones

DeclaracioacutenDefinicioacutenArgumentos formales y actualesLlamada y conversioacuten de argumentosValores devueltos

sect45 Estructuras

Declaracioacuten de estructurasInicializacioacutenOperaciones permitidasAcceso a miembrosEstructuras y funcionesMatrices de estructurasPunteros a estructurasEstructuras auto-referenciadas

sect46 Campos de Bits

sect47 Uniones

sect48 Enumeraciones

Expresiones

Asociatividad y precedencia de operadoresOrden de evaluacioacutenErrores y desbordamientosExpresiones con coma

sect49 Operadores

AritmeacuteticosAsignacioacutenManejo de BitsOperador ComaCondicionalOp de igualdadOp LoacutegicosModelado de tiposOp de PreprocesoOp de punteroRelacionalessizeoftypeidOp primariosOp antildeadidosOp UnitariosSobrecarga de OperadoresOperador Operador newOperador delete

sect410 Sentencias

Sentencias de etiqueta case defaultSentencias de seleccioacuten if hellip else else if switchSentencias de iteracioacuten while dowhile forSentencias de salto break continue goto return

sect411 Clases

CreacioacutenDeclaracioacutenNombres de ClasesAacutembito de nombresInstanciado de Clasesthis (palabra reservada)Miembros estaacuteticosClases polimoacuterficasFunciones virtualesFunciones dinaacutemicasClases abstractas

sect412 Plantillas

Funciones geneacutericasClases geneacutericas

Aunque las secciones anteriores describen completamente el lenguaje desde una perspectiva formal hemos antildeadido un capiacutetulo adicional (sect413) dedicado a los tecnicismos En eacutel se incluyen algunos consejos y reglas de buena praacutectica para la programacioacuten C++ asiacute como algunos idioms

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

41 Declaraciones

sect1 Sinopsis

Una declaracioacuten es una claacuteusula que introduce nombres en una unidad de compilacioacuten ( 142) o redeclara nombres introducidos por declaraciones previas La norma sentildeala que una declaracioacuten especifica la interpretacioacuten y atributos de estos nombres (como tipo de enlazado y de almacenamiento si es un objeto) asiacute como las condiciones para que una declaracioacuten no sea

tambieacuten una definicioacuten En la paacutegina adjunta se muestra su gramaacutetica ( Gramaacutetica)

Cada una de las introducciones unitarias que puede existir en una declaracioacuten es un declarador (declarator) Asiacute pues un declarador introduce un nombre o redeclara uno

declarado previamente La paacutegina adjunta muestra su gramaacutetica ( Gramaacutetica)

El presente capiacutetulo repasa este importante concepto y otros relacionados tales como objetos clases de almacenamiento tipos aacutembitovisibilidad duracioacuten y enlazado

El aacutembito visibilidad duracioacuten y enlazado son propiedades o caracteriacutesticas 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 definicioacuten de declaracioacuten o la exposicioacuten de su sintaxis

En el epiacutegrafe 4111 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 tambieacuten es dada a conocer mediante una declaracioacuten

411 Entidades

sect1 Presentacioacuten

En relacioacuten con los conceptos que aquiacute nos incumben consideramos que una entidad ( 121) 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 objeto-valor

Un algoritmo con informacioacuten sobre manipulacioacuten de datos Lo denominamos entidad-algoritmo o simplemente algoritmo

Respecto a los objetos-valor una posible clasificacioacuten podriacutea dividirlos en las siguientes categoriacuteas

Agregados

o matrizo estructurao unioacuteno clase unioacuten

Funciones Escalares

o Aritmeacuteticoo Enumeracioacuteno Booleanoo Punteroo Referencia

void

void ( 221) es un tipo especial con un valor muy particular ausencia de valor Los escalares son de caracteriacutesticas tales que su valor no pueden ser descompuestos en partes maacutes pequentildeas

por ejemplo un entero un valor loacutegico (cierto-falso) etc Las funciones ( 44) son principalmente algoritmo ya que estaacuten asociadas a ciertas operaciones (cierta computacioacuten) pero por convencioacuten se les puede asignar un valor es el que devuelven (puede ser void) Por su parte los agregados comparten la caracteriacutestica de que su valor puede ser descompuesto en elementos maacutes simples (escalares)

sect2 El papel de las declaraciones

Haciendo un siacutemil social podriacuteamos decir que las declaraciones son las encargadas de presentar al compilador cualquier entidad que deba existir en el programa Son por tanto el Chambelaacuten de la sociedad C++ Como en el caso de las presentaciones sociales esta presentacioacuten no se reduce a indicar el nombre tambieacuten puede sentildealarse algunas caracteriacutesticas 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

sect3 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 expresioacuten compleja que

represente uniacutevocamente al objeto ( 211 ) Cualquier intento de utilizar una declaracioacuten sin un nombre es un error aunque el nombre no tiene que responder necesariamente a un objeto o funcioacuten Ejemplo

extern int Errorchar Errorchar cptr Ok cptr nombre de punteroclass C Ok C nombre de clasetypedef unsigned int UINT Ok UINT alias para un tipo conocido

Ademaacutes del identificador las declaraciones de funciones pueden incluir ciertos atributos inline ( 4112a) virtual ( 4118a) y explicit ( 4112d1)

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 ( 21 ) Entre otros puede incluir los siguientes char wchar_t bool short int long signed unsigned float double void

Relativos al tipo de almacenamiento Determina el sitio en que se guarda el objeto y su

duracioacuten ( 213 ) 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 disquisicioacuten respecto a si un mismo objeto Por ejemplo una variable puede estar referenciado por dos identificadores distintos (que se refieren a la misma regioacuten de memoria) En la mayoriacutea de lenguajes de programacioacuten esta distincioacuten entre identificador y almacenamiento estaacute perfectamente establecida y suelen proporcionar mecanismos sintaacutecticos para que dos identificadores puedan referirse al mismo almacenamiento

412 Declaraciones y definiciones

sect1 Sinopsis

Utilizando un leacutexico formalista podemos decir que una declaracioacuten es una sentencia que

introduce un nombre en una unidad de compilacioacuten ( 142) daacutendole existencia semaacutentica Esto de la existencia semaacutentica es una forma elegante de decir que a partir de ahiacute el compilador sabe que cosa es (representa) ese nombre La forma de darle existencia semaacutentica a las entidades es declararlos (algo asiacute como presentarlos formalmente en el coacutedigo) Por ejemplo si declaramos una variable x o una funcioacuten func a partir de ahiacute el compilador sabe que x es una variable de tal tipo y que func es una funcioacuten de caracteriacutesticas cuales

El punto importante a resaltar aquiacute es que cada declaracioacuten asocia un nombre con un tipo de dato

lo que en C++ (una sociedad muy clasista 22) es importante ya que el conocimiento del tipo que corresponde a un identificador proporciona al compilador mucha informacioacuten sobre la entidad

representada por este (en muchas ocasiones casi toda la informacioacuten necesaria ) En especial el compilador dispone de una amplia informacioacuten acerca del uso de los tipos baacutesicos que operaciones son permitidas y que significado tienen estas operaciones

No olvidar que una declaracioacuten no hace nada maacutes que esto Es decir no antildeade ninguna otra informacioacuten distinta de relacionar una etiqueta con un tipo Posteriormente cuando esta etiqueta esteacute asociada con una entidad concreta (con una zona de memoria) las operaciones permitidas se

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

Ya hemos sentildealado que estas constantes (enumeradores) son de tipo entero por lo que pueden ser utilizadas en cualquier expresioacuten donde sean permitidas las constantes enteras Sus identificadores deben ser uacutenicos dentro del aacutembito de la declaracioacuten enum Se permiten inicializadores negativos los valores que adoptan los enumeradores suelen ser uacutenicos (aunque se permiten duplicidades) Para una visioacuten maacutes detallada de las declaraciones de estas constantes

ver enumeraciones ( 48 ) y la explicacioacuten que sigue sobre la palabra clave enum

sect2 Sintaxis

enum [ltnombre-de-tipogt] ltnombr-constgt [= ltvalorgt] [lista_var]

Puede omitirse la palabra clave enum siempre que el nemoacutenico ltnombre-de-tipogt no sea empleado para nada maacutes en el mismo aacutembito Ejemplo

calidad BUENA REGULAR MALA

En este caso el compilador presupone que calidad es un enumerador y no debe existir otra

definicioacuten en el mismo aacutembito de nombres En otras palabras calidad no debe utilizarse en el mismo aacutembito para designar otro objeto

ltnombre-de-tipogt es una etiqueta opcional que identifica al conjunto Puede omitirse si no se va a usar ninguna otra variable de este tipo de enumeracioacuten Ejemplo

enum CIERTO DUDOSO FALSO

ltnombr-constgt es el nombre de la constante de enumeracioacuten (enumerador) a la que opcionalmente puede asignarse el valor definido porltvalorgt En el ejemplo anterior son tres CIERTO DUDOSO y FALSO

ltvalorgt debe ser un entero (ya se ha sentildealado que los enumeradores son constantes

enteras) Si no se especifica ninguacuten valor se supone que es ltpreviogt + 1 donde ltpreviogt es el valor del enumerador anterior de la lista (el valor por defecto para el primero es cero) ltvalorgtpuede ser cualquier expresioacuten que resulte en un entero positivo o negativo (despueacutes de posible conversioacuten a entero)

ltlista_vargt 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 enumeracioacuten de nombre geneacuterico calidad las variables de este tipo pueden adoptar tres valores 0 1 y 2 identificados respectivamente por los nemoacutenicos BUENO REGULAR y MALO ademaacutes se definen dos variables del nuevo

tipo nota yestado

enum calidad BUENO REGULAR MALO nota estado

sect3 Descripcioacuten

La palabra clave enum define una enumeracioacuten 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 nemoacutenicos Por ejemplo la declaracioacuten

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 nemoacutenicos DOM LUNSAB Ademaacutes 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 nemoacutenicos ULT BW40 C40 BW80 C80 y MONO

Los valores asignados a los enumeradores dependen del formato de la declaracioacuten 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 Ademaacutes como puede comprobarse las expresiones de inicializacioacuten pueden incluir enumeradores previamente declarados

Los valores de los enumeradores no tienen porqueacute ser uacutenicos como en el ejemplo que sigue

enum estado BUENO MALO = 1 REGULAR = 1

326 Puntuadores

sect1 Sinopsis

Los signos de puntuacioacuten del lenguaje C++ juegan el mismo papel que sus homoacutenimos en el lenguaje natural escrito Conocidos tambieacuten comopuntuadores [1] son los que se citan a continuacioacuten La mayoriacutea de ellos tienen un doble uso y en ocasiones funcionan tambieacuten

comooperadores ( 49)

[ ] ( ) = ^ amp ndash + | ~ lt gt

sect2 Corchetes [ ]

Los corchetes indican subiacutendices de matrices uni y multi dimensionales

char ch str[] = Cadena de caracteresint mat[3][4] Matriz de 3 x 4ch = str[3] cuarto elemento

sect3 Pareacutentesis ( )

Los pareacutentesis sirven para agrupar expresiones alterar la precedencia normal de los operadores y su asociatividad aislar expresiones condicionales indicar llamadas a funciones y sentildealar los paraacutemetros de estas La sintaxis de C++ exige indefectiblemente el uso de pareacutentesis en muacuteltiples ocasiones En los ejemplos que siguen se muestran algunos usos

d = c (a + b) modifica la precedencia normalif (d == z) ++x imprescindible en la sentencia iffor (x =1 xlt10 x++) imprescindible en la sentencia forfunc() sentildeala llamada a funcioacutenint func() declara funcioacutenint (fptr)() declara puntero a funcioacutenfptr = func asigna valor al puntero

Observe que en el uacuteltimo caso la ausencia de pareacutentesis equivale a ampfunc ( 424a )

Se recomienda el uso de pareacutentesis en las macro-definiciones para evitar problemas potenciales en la expansioacuten Por ejemplo

define CUBO(x) ((x) (x) (x))

sect4 Llaves

Los pares de llaves sentildealan el comienzo y final de una sentencia compuesta es decir bloques de coacutedigo (grupos de sentencias que son tratadas como una unidad) Constituyen el segundo paso (despueacutes de las sentencias) en la estructuracioacuten y compartimentacioacuten del coacutedigo C++

if (d == z) ++x func()

Un bloque es una sentencia compuesta se trata de una sucesioacuten (que puede estar vaciacutea) de sentencias delimitadas por un par de corchetes Desde el punto de vista sintaacutectico un bloque puede ser considerado como una sola sentencia Juega un papel importante en el aacutembito (scope) de los identificadores puesto que un identificador declarado dentro de un bloque tiene un aacutembito

que comienza en el punto de la declaracioacuten 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)

Despueacutes del corchete de cierre no se necesita el punto y coma de fin de sentencia

if (statement) punto y coma ilegal else

Nota las llaves sirven tambieacuten en C++ para otros usos distintos de la pura delimitacioacuten de bloques de coacutedigo Por ejemplo en la definicioacuten de estructuras uniones y clases en cuyo caso si puede ser necesaria la inclusioacuten del punto y coma despueacutes de la llave de cierre

sect5 Coma

La coma como puntuador se utiliza para separar los elementos en las listas de paraacutemetros de una funcioacuten

void func(int n float f char ch)

La coma se usa tambieacuten como un operador en las expresiones con coma ( 4105) Es posible mezclar los dos usos (separador en lista de paraacutemetros y operador) pero deben usarse pareacutentesis para distinguirlos

sect6 Punto y coma

El punto y coma es el signo de fin de sentencia Cualquier expresioacuten legal C++ terminada por un punto y coma (incluyendo la expresioacuten vaciacutea - un punto y coma aislado-) es interpretado como una

sentencia conocidas como sentencia-expresioacuten ( 410) La expresioacuten se evaluacutea y el resultado se descarta si no tiene efectos colaterales C++ la ignora

a + b evaluacutea a + b descarta el resultado++a efecto lateral en a se descarta el valor ++a expresioacuten vaciacutea = sentencia nula

El punto y coma se usa a veces para crear sentencias nulas

for (i = 0 i lt n i++) sentencia nula (hacer nada)

sect7 Dos puntos

Los dos puntos se utilizan para sentildealar sentencias etiquetadas ( 4101)

comienzo x=0 comienzo es la etiquetagoto comienzo

sect8 Puntos suspensivos

Los puntos suspensivos tambieacuten 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 nuacutemero variable de argumentos o pueden ser de tipo variable ( 441) Por ejemplo

void func(int n char ch)

Este prototipo de funcioacuten declara que func estaacute definida de modo que debe ser llamada con al

menos dos argumentos un int y un char Ademaacutes puede tener un cierto nuacutemero de argumentos adicionales (puede omitirse la coma antes de la elipsis)

Se utiliza tambieacuten para indicar que un manejador de excepciones (handler) puede capturar una

excepcioacuten de cualquier tipo ( 162) Ejemplo

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

Nota como podeacuteis ver en ocasiones mi uso particular en los ejemplos de los tres puntos es para indicar cualquier nuacutemero de sentencias Espero que no sea motivo de confusioacuten Desde luego en el caso anterior seriacutea maacutes correcta la notacioacuten

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

sect9 Asterisco

El asterisco puede ser utilizado en C++ de tres formas como una declaracioacuten de tipo de variable

(variable de puntero 42 ) como operador de indireccioacuten (tambieacuten llamado operador

de dereferencia 4911a) y como operador de multiplicacioacuten

Ejemplos

char char_ptr declara puntero a caraacutecterx = int_ptr operador de indireccioacutenl = 2 314 r operador multiplicacioacuten

sect10 Signo igual =

El signo igual = separa la declaracioacuten de variables de las listas de inicializacioacuten

char array[5] = 1 2 3 4 5

Recordemos que al contrario que en C donde las declaraciones no pueden estar precedidas por ninguacuten coacutedigo deben ir al principio en C++ las declaraciones de cualquier tipo pueden aparecer en cualquier punto del coacutedigo (con algunas restricciones)

En la lista de argumentos de una funcioacuten el signo igual indica el valor por defecto para un paraacutemetro

int f(int i = 0) el valor por defecto de k es cero

El signo igual es tambieacuten utilizado como operador de asignacioacuten ( 492) Ejemplo

x = yz += 5

sect11 Almohadilla

Si la almohadilla aparecen en el primer caraacutecter (distinto de espacio en blanco) de una liacutenea

sentildeala directivas de preproceso ( 4910) En este caso es un operador especiacutefico de la fase

de preproceso del coacutedigo fuente Significa una opcioacuten del preprocesador ( 14) que no tiene porqueacute estar asociada necesariamente a generacioacuten de coacutedigo Las directivas se situacutean generalmente al comienzo del programa aunque legalmente pueden aparecer en cualquier punto

Ejemplos de directivas de preproceso

(null directive)define NULO 0include ltstdiohgt

4 Estructura del lenguaje

sect1 Sinopsis

Esta parte proporciona una definicioacuten formal del lenguaje C++ describiendo las formas en que

pueden agruparse correctamente los tokens ( 32) palabras que constituyen el lenguaje entendible por el compilador para formar declaraciones expresiones y otras unidades significativas Para su anaacutelisis lo hemos descompuesto en 13 grupos seguacuten la clasificacioacuten que sigue

sect41 Declaraciones

ObjetosReferencias amp definicionesDefinicioacuten provisionalAacutembitoVisibilidadDuracioacutenUnidad de compilacioacutenEnlazado

Sintaxis de declaraciones

Conversiones aritmeacuteticasInicializacioacutenEspecificadores de clase de almacenamientoModificadores auxiliaresModificadores de funcioacuten

sect42 Punteros

Puntero a objetoDeclaracioacuten de punterosAritmeacutetica de punterosReferenciasPuntero a funcioacuten

sect43 Matrices

Declaracioacuten de matricesMatrices alfanumeacutericasMatrices de punterosMatrices de matrices

sect44 Funciones

DeclaracioacutenDefinicioacutenArgumentos formales y actualesLlamada y conversioacuten de argumentosValores devueltos

sect45 Estructuras

Declaracioacuten de estructurasInicializacioacutenOperaciones permitidasAcceso a miembrosEstructuras y funcionesMatrices de estructurasPunteros a estructurasEstructuras auto-referenciadas

sect46 Campos de Bits

sect47 Uniones

sect48 Enumeraciones

Expresiones

Asociatividad y precedencia de operadoresOrden de evaluacioacutenErrores y desbordamientosExpresiones con coma

sect49 Operadores

AritmeacuteticosAsignacioacutenManejo de BitsOperador ComaCondicionalOp de igualdadOp LoacutegicosModelado de tiposOp de PreprocesoOp de punteroRelacionalessizeoftypeidOp primariosOp antildeadidosOp UnitariosSobrecarga de OperadoresOperador Operador newOperador delete

sect410 Sentencias

Sentencias de etiqueta case defaultSentencias de seleccioacuten if hellip else else if switchSentencias de iteracioacuten while dowhile forSentencias de salto break continue goto return

sect411 Clases

CreacioacutenDeclaracioacutenNombres de ClasesAacutembito de nombresInstanciado de Clasesthis (palabra reservada)Miembros estaacuteticosClases polimoacuterficasFunciones virtualesFunciones dinaacutemicasClases abstractas

sect412 Plantillas

Funciones geneacutericasClases geneacutericas

Aunque las secciones anteriores describen completamente el lenguaje desde una perspectiva formal hemos antildeadido un capiacutetulo adicional (sect413) dedicado a los tecnicismos En eacutel se incluyen algunos consejos y reglas de buena praacutectica para la programacioacuten C++ asiacute como algunos idioms

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

41 Declaraciones

sect1 Sinopsis

Una declaracioacuten es una claacuteusula que introduce nombres en una unidad de compilacioacuten ( 142) o redeclara nombres introducidos por declaraciones previas La norma sentildeala que una declaracioacuten especifica la interpretacioacuten y atributos de estos nombres (como tipo de enlazado y de almacenamiento si es un objeto) asiacute como las condiciones para que una declaracioacuten no sea

tambieacuten una definicioacuten En la paacutegina adjunta se muestra su gramaacutetica ( Gramaacutetica)

Cada una de las introducciones unitarias que puede existir en una declaracioacuten es un declarador (declarator) Asiacute pues un declarador introduce un nombre o redeclara uno

declarado previamente La paacutegina adjunta muestra su gramaacutetica ( Gramaacutetica)

El presente capiacutetulo repasa este importante concepto y otros relacionados tales como objetos clases de almacenamiento tipos aacutembitovisibilidad duracioacuten y enlazado

El aacutembito visibilidad duracioacuten y enlazado son propiedades o caracteriacutesticas 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 definicioacuten de declaracioacuten o la exposicioacuten de su sintaxis

En el epiacutegrafe 4111 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 tambieacuten es dada a conocer mediante una declaracioacuten

411 Entidades

sect1 Presentacioacuten

En relacioacuten con los conceptos que aquiacute nos incumben consideramos que una entidad ( 121) 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 objeto-valor

Un algoritmo con informacioacuten sobre manipulacioacuten de datos Lo denominamos entidad-algoritmo o simplemente algoritmo

Respecto a los objetos-valor una posible clasificacioacuten podriacutea dividirlos en las siguientes categoriacuteas

Agregados

o matrizo estructurao unioacuteno clase unioacuten

Funciones Escalares

o Aritmeacuteticoo Enumeracioacuteno Booleanoo Punteroo Referencia

void

void ( 221) es un tipo especial con un valor muy particular ausencia de valor Los escalares son de caracteriacutesticas tales que su valor no pueden ser descompuestos en partes maacutes pequentildeas

por ejemplo un entero un valor loacutegico (cierto-falso) etc Las funciones ( 44) son principalmente algoritmo ya que estaacuten asociadas a ciertas operaciones (cierta computacioacuten) pero por convencioacuten se les puede asignar un valor es el que devuelven (puede ser void) Por su parte los agregados comparten la caracteriacutestica de que su valor puede ser descompuesto en elementos maacutes simples (escalares)

sect2 El papel de las declaraciones

Haciendo un siacutemil social podriacuteamos decir que las declaraciones son las encargadas de presentar al compilador cualquier entidad que deba existir en el programa Son por tanto el Chambelaacuten de la sociedad C++ Como en el caso de las presentaciones sociales esta presentacioacuten no se reduce a indicar el nombre tambieacuten puede sentildealarse algunas caracteriacutesticas 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

sect3 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 expresioacuten compleja que

represente uniacutevocamente al objeto ( 211 ) Cualquier intento de utilizar una declaracioacuten sin un nombre es un error aunque el nombre no tiene que responder necesariamente a un objeto o funcioacuten Ejemplo

extern int Errorchar Errorchar cptr Ok cptr nombre de punteroclass C Ok C nombre de clasetypedef unsigned int UINT Ok UINT alias para un tipo conocido

Ademaacutes del identificador las declaraciones de funciones pueden incluir ciertos atributos inline ( 4112a) virtual ( 4118a) y explicit ( 4112d1)

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 ( 21 ) Entre otros puede incluir los siguientes char wchar_t bool short int long signed unsigned float double void

Relativos al tipo de almacenamiento Determina el sitio en que se guarda el objeto y su

duracioacuten ( 213 ) 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 disquisicioacuten respecto a si un mismo objeto Por ejemplo una variable puede estar referenciado por dos identificadores distintos (que se refieren a la misma regioacuten de memoria) En la mayoriacutea de lenguajes de programacioacuten esta distincioacuten entre identificador y almacenamiento estaacute perfectamente establecida y suelen proporcionar mecanismos sintaacutecticos para que dos identificadores puedan referirse al mismo almacenamiento

412 Declaraciones y definiciones

sect1 Sinopsis

Utilizando un leacutexico formalista podemos decir que una declaracioacuten es una sentencia que

introduce un nombre en una unidad de compilacioacuten ( 142) daacutendole existencia semaacutentica Esto de la existencia semaacutentica es una forma elegante de decir que a partir de ahiacute el compilador sabe que cosa es (representa) ese nombre La forma de darle existencia semaacutentica a las entidades es declararlos (algo asiacute como presentarlos formalmente en el coacutedigo) Por ejemplo si declaramos una variable x o una funcioacuten func a partir de ahiacute el compilador sabe que x es una variable de tal tipo y que func es una funcioacuten de caracteriacutesticas cuales

El punto importante a resaltar aquiacute es que cada declaracioacuten asocia un nombre con un tipo de dato

lo que en C++ (una sociedad muy clasista 22) es importante ya que el conocimiento del tipo que corresponde a un identificador proporciona al compilador mucha informacioacuten sobre la entidad

representada por este (en muchas ocasiones casi toda la informacioacuten necesaria ) En especial el compilador dispone de una amplia informacioacuten acerca del uso de los tipos baacutesicos que operaciones son permitidas y que significado tienen estas operaciones

No olvidar que una declaracioacuten no hace nada maacutes que esto Es decir no antildeade ninguna otra informacioacuten distinta de relacionar una etiqueta con un tipo Posteriormente cuando esta etiqueta esteacute asociada con una entidad concreta (con una zona de memoria) las operaciones permitidas se

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

La palabra clave enum define una enumeracioacuten 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 nemoacutenicos Por ejemplo la declaracioacuten

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 nemoacutenicos DOM LUNSAB Ademaacutes 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 nemoacutenicos ULT BW40 C40 BW80 C80 y MONO

Los valores asignados a los enumeradores dependen del formato de la declaracioacuten 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 Ademaacutes como puede comprobarse las expresiones de inicializacioacuten pueden incluir enumeradores previamente declarados

Los valores de los enumeradores no tienen porqueacute ser uacutenicos como en el ejemplo que sigue

enum estado BUENO MALO = 1 REGULAR = 1

326 Puntuadores

sect1 Sinopsis

Los signos de puntuacioacuten del lenguaje C++ juegan el mismo papel que sus homoacutenimos en el lenguaje natural escrito Conocidos tambieacuten comopuntuadores [1] son los que se citan a continuacioacuten La mayoriacutea de ellos tienen un doble uso y en ocasiones funcionan tambieacuten

comooperadores ( 49)

[ ] ( ) = ^ amp ndash + | ~ lt gt

sect2 Corchetes [ ]

Los corchetes indican subiacutendices de matrices uni y multi dimensionales

char ch str[] = Cadena de caracteresint mat[3][4] Matriz de 3 x 4ch = str[3] cuarto elemento

sect3 Pareacutentesis ( )

Los pareacutentesis sirven para agrupar expresiones alterar la precedencia normal de los operadores y su asociatividad aislar expresiones condicionales indicar llamadas a funciones y sentildealar los paraacutemetros de estas La sintaxis de C++ exige indefectiblemente el uso de pareacutentesis en muacuteltiples ocasiones En los ejemplos que siguen se muestran algunos usos

d = c (a + b) modifica la precedencia normalif (d == z) ++x imprescindible en la sentencia iffor (x =1 xlt10 x++) imprescindible en la sentencia forfunc() sentildeala llamada a funcioacutenint func() declara funcioacutenint (fptr)() declara puntero a funcioacutenfptr = func asigna valor al puntero

Observe que en el uacuteltimo caso la ausencia de pareacutentesis equivale a ampfunc ( 424a )

Se recomienda el uso de pareacutentesis en las macro-definiciones para evitar problemas potenciales en la expansioacuten Por ejemplo

define CUBO(x) ((x) (x) (x))

sect4 Llaves

Los pares de llaves sentildealan el comienzo y final de una sentencia compuesta es decir bloques de coacutedigo (grupos de sentencias que son tratadas como una unidad) Constituyen el segundo paso (despueacutes de las sentencias) en la estructuracioacuten y compartimentacioacuten del coacutedigo C++

if (d == z) ++x func()

Un bloque es una sentencia compuesta se trata de una sucesioacuten (que puede estar vaciacutea) de sentencias delimitadas por un par de corchetes Desde el punto de vista sintaacutectico un bloque puede ser considerado como una sola sentencia Juega un papel importante en el aacutembito (scope) de los identificadores puesto que un identificador declarado dentro de un bloque tiene un aacutembito

que comienza en el punto de la declaracioacuten 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)

Despueacutes del corchete de cierre no se necesita el punto y coma de fin de sentencia

if (statement) punto y coma ilegal else

Nota las llaves sirven tambieacuten en C++ para otros usos distintos de la pura delimitacioacuten de bloques de coacutedigo Por ejemplo en la definicioacuten de estructuras uniones y clases en cuyo caso si puede ser necesaria la inclusioacuten del punto y coma despueacutes de la llave de cierre

sect5 Coma

La coma como puntuador se utiliza para separar los elementos en las listas de paraacutemetros de una funcioacuten

void func(int n float f char ch)

La coma se usa tambieacuten como un operador en las expresiones con coma ( 4105) Es posible mezclar los dos usos (separador en lista de paraacutemetros y operador) pero deben usarse pareacutentesis para distinguirlos

sect6 Punto y coma

El punto y coma es el signo de fin de sentencia Cualquier expresioacuten legal C++ terminada por un punto y coma (incluyendo la expresioacuten vaciacutea - un punto y coma aislado-) es interpretado como una

sentencia conocidas como sentencia-expresioacuten ( 410) La expresioacuten se evaluacutea y el resultado se descarta si no tiene efectos colaterales C++ la ignora

a + b evaluacutea a + b descarta el resultado++a efecto lateral en a se descarta el valor ++a expresioacuten vaciacutea = sentencia nula

El punto y coma se usa a veces para crear sentencias nulas

for (i = 0 i lt n i++) sentencia nula (hacer nada)

sect7 Dos puntos

Los dos puntos se utilizan para sentildealar sentencias etiquetadas ( 4101)

comienzo x=0 comienzo es la etiquetagoto comienzo

sect8 Puntos suspensivos

Los puntos suspensivos tambieacuten 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 nuacutemero variable de argumentos o pueden ser de tipo variable ( 441) Por ejemplo

void func(int n char ch)

Este prototipo de funcioacuten declara que func estaacute definida de modo que debe ser llamada con al

menos dos argumentos un int y un char Ademaacutes puede tener un cierto nuacutemero de argumentos adicionales (puede omitirse la coma antes de la elipsis)

Se utiliza tambieacuten para indicar que un manejador de excepciones (handler) puede capturar una

excepcioacuten de cualquier tipo ( 162) Ejemplo

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

Nota como podeacuteis ver en ocasiones mi uso particular en los ejemplos de los tres puntos es para indicar cualquier nuacutemero de sentencias Espero que no sea motivo de confusioacuten Desde luego en el caso anterior seriacutea maacutes correcta la notacioacuten

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

sect9 Asterisco

El asterisco puede ser utilizado en C++ de tres formas como una declaracioacuten de tipo de variable

(variable de puntero 42 ) como operador de indireccioacuten (tambieacuten llamado operador

de dereferencia 4911a) y como operador de multiplicacioacuten

Ejemplos

char char_ptr declara puntero a caraacutecterx = int_ptr operador de indireccioacutenl = 2 314 r operador multiplicacioacuten

sect10 Signo igual =

El signo igual = separa la declaracioacuten de variables de las listas de inicializacioacuten

char array[5] = 1 2 3 4 5

Recordemos que al contrario que en C donde las declaraciones no pueden estar precedidas por ninguacuten coacutedigo deben ir al principio en C++ las declaraciones de cualquier tipo pueden aparecer en cualquier punto del coacutedigo (con algunas restricciones)

En la lista de argumentos de una funcioacuten el signo igual indica el valor por defecto para un paraacutemetro

int f(int i = 0) el valor por defecto de k es cero

El signo igual es tambieacuten utilizado como operador de asignacioacuten ( 492) Ejemplo

x = yz += 5

sect11 Almohadilla

Si la almohadilla aparecen en el primer caraacutecter (distinto de espacio en blanco) de una liacutenea

sentildeala directivas de preproceso ( 4910) En este caso es un operador especiacutefico de la fase

de preproceso del coacutedigo fuente Significa una opcioacuten del preprocesador ( 14) que no tiene porqueacute estar asociada necesariamente a generacioacuten de coacutedigo Las directivas se situacutean generalmente al comienzo del programa aunque legalmente pueden aparecer en cualquier punto

Ejemplos de directivas de preproceso

(null directive)define NULO 0include ltstdiohgt

4 Estructura del lenguaje

sect1 Sinopsis

Esta parte proporciona una definicioacuten formal del lenguaje C++ describiendo las formas en que

pueden agruparse correctamente los tokens ( 32) palabras que constituyen el lenguaje entendible por el compilador para formar declaraciones expresiones y otras unidades significativas Para su anaacutelisis lo hemos descompuesto en 13 grupos seguacuten la clasificacioacuten que sigue

sect41 Declaraciones

ObjetosReferencias amp definicionesDefinicioacuten provisionalAacutembitoVisibilidadDuracioacutenUnidad de compilacioacutenEnlazado

Sintaxis de declaraciones

Conversiones aritmeacuteticasInicializacioacutenEspecificadores de clase de almacenamientoModificadores auxiliaresModificadores de funcioacuten

sect42 Punteros

Puntero a objetoDeclaracioacuten de punterosAritmeacutetica de punterosReferenciasPuntero a funcioacuten

sect43 Matrices

Declaracioacuten de matricesMatrices alfanumeacutericasMatrices de punterosMatrices de matrices

sect44 Funciones

DeclaracioacutenDefinicioacutenArgumentos formales y actualesLlamada y conversioacuten de argumentosValores devueltos

sect45 Estructuras

Declaracioacuten de estructurasInicializacioacutenOperaciones permitidasAcceso a miembrosEstructuras y funcionesMatrices de estructurasPunteros a estructurasEstructuras auto-referenciadas

sect46 Campos de Bits

sect47 Uniones

sect48 Enumeraciones

Expresiones

Asociatividad y precedencia de operadoresOrden de evaluacioacutenErrores y desbordamientosExpresiones con coma

sect49 Operadores

AritmeacuteticosAsignacioacutenManejo de BitsOperador ComaCondicionalOp de igualdadOp LoacutegicosModelado de tiposOp de PreprocesoOp de punteroRelacionalessizeoftypeidOp primariosOp antildeadidosOp UnitariosSobrecarga de OperadoresOperador Operador newOperador delete

sect410 Sentencias

Sentencias de etiqueta case defaultSentencias de seleccioacuten if hellip else else if switchSentencias de iteracioacuten while dowhile forSentencias de salto break continue goto return

sect411 Clases

CreacioacutenDeclaracioacutenNombres de ClasesAacutembito de nombresInstanciado de Clasesthis (palabra reservada)Miembros estaacuteticosClases polimoacuterficasFunciones virtualesFunciones dinaacutemicasClases abstractas

sect412 Plantillas

Funciones geneacutericasClases geneacutericas

Aunque las secciones anteriores describen completamente el lenguaje desde una perspectiva formal hemos antildeadido un capiacutetulo adicional (sect413) dedicado a los tecnicismos En eacutel se incluyen algunos consejos y reglas de buena praacutectica para la programacioacuten C++ asiacute como algunos idioms

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

41 Declaraciones

sect1 Sinopsis

Una declaracioacuten es una claacuteusula que introduce nombres en una unidad de compilacioacuten ( 142) o redeclara nombres introducidos por declaraciones previas La norma sentildeala que una declaracioacuten especifica la interpretacioacuten y atributos de estos nombres (como tipo de enlazado y de almacenamiento si es un objeto) asiacute como las condiciones para que una declaracioacuten no sea

tambieacuten una definicioacuten En la paacutegina adjunta se muestra su gramaacutetica ( Gramaacutetica)

Cada una de las introducciones unitarias que puede existir en una declaracioacuten es un declarador (declarator) Asiacute pues un declarador introduce un nombre o redeclara uno

declarado previamente La paacutegina adjunta muestra su gramaacutetica ( Gramaacutetica)

El presente capiacutetulo repasa este importante concepto y otros relacionados tales como objetos clases de almacenamiento tipos aacutembitovisibilidad duracioacuten y enlazado

El aacutembito visibilidad duracioacuten y enlazado son propiedades o caracteriacutesticas 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 definicioacuten de declaracioacuten o la exposicioacuten de su sintaxis

En el epiacutegrafe 4111 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 tambieacuten es dada a conocer mediante una declaracioacuten

411 Entidades

sect1 Presentacioacuten

En relacioacuten con los conceptos que aquiacute nos incumben consideramos que una entidad ( 121) 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 objeto-valor

Un algoritmo con informacioacuten sobre manipulacioacuten de datos Lo denominamos entidad-algoritmo o simplemente algoritmo

Respecto a los objetos-valor una posible clasificacioacuten podriacutea dividirlos en las siguientes categoriacuteas

Agregados

o matrizo estructurao unioacuteno clase unioacuten

Funciones Escalares

o Aritmeacuteticoo Enumeracioacuteno Booleanoo Punteroo Referencia

void

void ( 221) es un tipo especial con un valor muy particular ausencia de valor Los escalares son de caracteriacutesticas tales que su valor no pueden ser descompuestos en partes maacutes pequentildeas

por ejemplo un entero un valor loacutegico (cierto-falso) etc Las funciones ( 44) son principalmente algoritmo ya que estaacuten asociadas a ciertas operaciones (cierta computacioacuten) pero por convencioacuten se les puede asignar un valor es el que devuelven (puede ser void) Por su parte los agregados comparten la caracteriacutestica de que su valor puede ser descompuesto en elementos maacutes simples (escalares)

sect2 El papel de las declaraciones

Haciendo un siacutemil social podriacuteamos decir que las declaraciones son las encargadas de presentar al compilador cualquier entidad que deba existir en el programa Son por tanto el Chambelaacuten de la sociedad C++ Como en el caso de las presentaciones sociales esta presentacioacuten no se reduce a indicar el nombre tambieacuten puede sentildealarse algunas caracteriacutesticas 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

sect3 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 expresioacuten compleja que

represente uniacutevocamente al objeto ( 211 ) Cualquier intento de utilizar una declaracioacuten sin un nombre es un error aunque el nombre no tiene que responder necesariamente a un objeto o funcioacuten Ejemplo

extern int Errorchar Errorchar cptr Ok cptr nombre de punteroclass C Ok C nombre de clasetypedef unsigned int UINT Ok UINT alias para un tipo conocido

Ademaacutes del identificador las declaraciones de funciones pueden incluir ciertos atributos inline ( 4112a) virtual ( 4118a) y explicit ( 4112d1)

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 ( 21 ) Entre otros puede incluir los siguientes char wchar_t bool short int long signed unsigned float double void

Relativos al tipo de almacenamiento Determina el sitio en que se guarda el objeto y su

duracioacuten ( 213 ) 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 disquisicioacuten respecto a si un mismo objeto Por ejemplo una variable puede estar referenciado por dos identificadores distintos (que se refieren a la misma regioacuten de memoria) En la mayoriacutea de lenguajes de programacioacuten esta distincioacuten entre identificador y almacenamiento estaacute perfectamente establecida y suelen proporcionar mecanismos sintaacutecticos para que dos identificadores puedan referirse al mismo almacenamiento

412 Declaraciones y definiciones

sect1 Sinopsis

Utilizando un leacutexico formalista podemos decir que una declaracioacuten es una sentencia que

introduce un nombre en una unidad de compilacioacuten ( 142) daacutendole existencia semaacutentica Esto de la existencia semaacutentica es una forma elegante de decir que a partir de ahiacute el compilador sabe que cosa es (representa) ese nombre La forma de darle existencia semaacutentica a las entidades es declararlos (algo asiacute como presentarlos formalmente en el coacutedigo) Por ejemplo si declaramos una variable x o una funcioacuten func a partir de ahiacute el compilador sabe que x es una variable de tal tipo y que func es una funcioacuten de caracteriacutesticas cuales

El punto importante a resaltar aquiacute es que cada declaracioacuten asocia un nombre con un tipo de dato

lo que en C++ (una sociedad muy clasista 22) es importante ya que el conocimiento del tipo que corresponde a un identificador proporciona al compilador mucha informacioacuten sobre la entidad

representada por este (en muchas ocasiones casi toda la informacioacuten necesaria ) En especial el compilador dispone de una amplia informacioacuten acerca del uso de los tipos baacutesicos que operaciones son permitidas y que significado tienen estas operaciones

No olvidar que una declaracioacuten no hace nada maacutes que esto Es decir no antildeade ninguna otra informacioacuten distinta de relacionar una etiqueta con un tipo Posteriormente cuando esta etiqueta esteacute asociada con una entidad concreta (con una zona de memoria) las operaciones permitidas se

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

[ ] ( ) = ^ amp ndash + | ~ lt gt

sect2 Corchetes [ ]

Los corchetes indican subiacutendices de matrices uni y multi dimensionales

char ch str[] = Cadena de caracteresint mat[3][4] Matriz de 3 x 4ch = str[3] cuarto elemento

sect3 Pareacutentesis ( )

Los pareacutentesis sirven para agrupar expresiones alterar la precedencia normal de los operadores y su asociatividad aislar expresiones condicionales indicar llamadas a funciones y sentildealar los paraacutemetros de estas La sintaxis de C++ exige indefectiblemente el uso de pareacutentesis en muacuteltiples ocasiones En los ejemplos que siguen se muestran algunos usos

d = c (a + b) modifica la precedencia normalif (d == z) ++x imprescindible en la sentencia iffor (x =1 xlt10 x++) imprescindible en la sentencia forfunc() sentildeala llamada a funcioacutenint func() declara funcioacutenint (fptr)() declara puntero a funcioacutenfptr = func asigna valor al puntero

Observe que en el uacuteltimo caso la ausencia de pareacutentesis equivale a ampfunc ( 424a )

Se recomienda el uso de pareacutentesis en las macro-definiciones para evitar problemas potenciales en la expansioacuten Por ejemplo

define CUBO(x) ((x) (x) (x))

sect4 Llaves

Los pares de llaves sentildealan el comienzo y final de una sentencia compuesta es decir bloques de coacutedigo (grupos de sentencias que son tratadas como una unidad) Constituyen el segundo paso (despueacutes de las sentencias) en la estructuracioacuten y compartimentacioacuten del coacutedigo C++

if (d == z) ++x func()

Un bloque es una sentencia compuesta se trata de una sucesioacuten (que puede estar vaciacutea) de sentencias delimitadas por un par de corchetes Desde el punto de vista sintaacutectico un bloque puede ser considerado como una sola sentencia Juega un papel importante en el aacutembito (scope) de los identificadores puesto que un identificador declarado dentro de un bloque tiene un aacutembito

que comienza en el punto de la declaracioacuten 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)

Despueacutes del corchete de cierre no se necesita el punto y coma de fin de sentencia

if (statement) punto y coma ilegal else

Nota las llaves sirven tambieacuten en C++ para otros usos distintos de la pura delimitacioacuten de bloques de coacutedigo Por ejemplo en la definicioacuten de estructuras uniones y clases en cuyo caso si puede ser necesaria la inclusioacuten del punto y coma despueacutes de la llave de cierre

sect5 Coma

La coma como puntuador se utiliza para separar los elementos en las listas de paraacutemetros de una funcioacuten

void func(int n float f char ch)

La coma se usa tambieacuten como un operador en las expresiones con coma ( 4105) Es posible mezclar los dos usos (separador en lista de paraacutemetros y operador) pero deben usarse pareacutentesis para distinguirlos

sect6 Punto y coma

El punto y coma es el signo de fin de sentencia Cualquier expresioacuten legal C++ terminada por un punto y coma (incluyendo la expresioacuten vaciacutea - un punto y coma aislado-) es interpretado como una

sentencia conocidas como sentencia-expresioacuten ( 410) La expresioacuten se evaluacutea y el resultado se descarta si no tiene efectos colaterales C++ la ignora

a + b evaluacutea a + b descarta el resultado++a efecto lateral en a se descarta el valor ++a expresioacuten vaciacutea = sentencia nula

El punto y coma se usa a veces para crear sentencias nulas

for (i = 0 i lt n i++) sentencia nula (hacer nada)

sect7 Dos puntos

Los dos puntos se utilizan para sentildealar sentencias etiquetadas ( 4101)

comienzo x=0 comienzo es la etiquetagoto comienzo

sect8 Puntos suspensivos

Los puntos suspensivos tambieacuten 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 nuacutemero variable de argumentos o pueden ser de tipo variable ( 441) Por ejemplo

void func(int n char ch)

Este prototipo de funcioacuten declara que func estaacute definida de modo que debe ser llamada con al

menos dos argumentos un int y un char Ademaacutes puede tener un cierto nuacutemero de argumentos adicionales (puede omitirse la coma antes de la elipsis)

Se utiliza tambieacuten para indicar que un manejador de excepciones (handler) puede capturar una

excepcioacuten de cualquier tipo ( 162) Ejemplo

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

Nota como podeacuteis ver en ocasiones mi uso particular en los ejemplos de los tres puntos es para indicar cualquier nuacutemero de sentencias Espero que no sea motivo de confusioacuten Desde luego en el caso anterior seriacutea maacutes correcta la notacioacuten

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

sect9 Asterisco

El asterisco puede ser utilizado en C++ de tres formas como una declaracioacuten de tipo de variable

(variable de puntero 42 ) como operador de indireccioacuten (tambieacuten llamado operador

de dereferencia 4911a) y como operador de multiplicacioacuten

Ejemplos

char char_ptr declara puntero a caraacutecterx = int_ptr operador de indireccioacutenl = 2 314 r operador multiplicacioacuten

sect10 Signo igual =

El signo igual = separa la declaracioacuten de variables de las listas de inicializacioacuten

char array[5] = 1 2 3 4 5

Recordemos que al contrario que en C donde las declaraciones no pueden estar precedidas por ninguacuten coacutedigo deben ir al principio en C++ las declaraciones de cualquier tipo pueden aparecer en cualquier punto del coacutedigo (con algunas restricciones)

En la lista de argumentos de una funcioacuten el signo igual indica el valor por defecto para un paraacutemetro

int f(int i = 0) el valor por defecto de k es cero

El signo igual es tambieacuten utilizado como operador de asignacioacuten ( 492) Ejemplo

x = yz += 5

sect11 Almohadilla

Si la almohadilla aparecen en el primer caraacutecter (distinto de espacio en blanco) de una liacutenea

sentildeala directivas de preproceso ( 4910) En este caso es un operador especiacutefico de la fase

de preproceso del coacutedigo fuente Significa una opcioacuten del preprocesador ( 14) que no tiene porqueacute estar asociada necesariamente a generacioacuten de coacutedigo Las directivas se situacutean generalmente al comienzo del programa aunque legalmente pueden aparecer en cualquier punto

Ejemplos de directivas de preproceso

(null directive)define NULO 0include ltstdiohgt

4 Estructura del lenguaje

sect1 Sinopsis

Esta parte proporciona una definicioacuten formal del lenguaje C++ describiendo las formas en que

pueden agruparse correctamente los tokens ( 32) palabras que constituyen el lenguaje entendible por el compilador para formar declaraciones expresiones y otras unidades significativas Para su anaacutelisis lo hemos descompuesto en 13 grupos seguacuten la clasificacioacuten que sigue

sect41 Declaraciones

ObjetosReferencias amp definicionesDefinicioacuten provisionalAacutembitoVisibilidadDuracioacutenUnidad de compilacioacutenEnlazado

Sintaxis de declaraciones

Conversiones aritmeacuteticasInicializacioacutenEspecificadores de clase de almacenamientoModificadores auxiliaresModificadores de funcioacuten

sect42 Punteros

Puntero a objetoDeclaracioacuten de punterosAritmeacutetica de punterosReferenciasPuntero a funcioacuten

sect43 Matrices

Declaracioacuten de matricesMatrices alfanumeacutericasMatrices de punterosMatrices de matrices

sect44 Funciones

DeclaracioacutenDefinicioacutenArgumentos formales y actualesLlamada y conversioacuten de argumentosValores devueltos

sect45 Estructuras

Declaracioacuten de estructurasInicializacioacutenOperaciones permitidasAcceso a miembrosEstructuras y funcionesMatrices de estructurasPunteros a estructurasEstructuras auto-referenciadas

sect46 Campos de Bits

sect47 Uniones

sect48 Enumeraciones

Expresiones

Asociatividad y precedencia de operadoresOrden de evaluacioacutenErrores y desbordamientosExpresiones con coma

sect49 Operadores

AritmeacuteticosAsignacioacutenManejo de BitsOperador ComaCondicionalOp de igualdadOp LoacutegicosModelado de tiposOp de PreprocesoOp de punteroRelacionalessizeoftypeidOp primariosOp antildeadidosOp UnitariosSobrecarga de OperadoresOperador Operador newOperador delete

sect410 Sentencias

Sentencias de etiqueta case defaultSentencias de seleccioacuten if hellip else else if switchSentencias de iteracioacuten while dowhile forSentencias de salto break continue goto return

sect411 Clases

CreacioacutenDeclaracioacutenNombres de ClasesAacutembito de nombresInstanciado de Clasesthis (palabra reservada)Miembros estaacuteticosClases polimoacuterficasFunciones virtualesFunciones dinaacutemicasClases abstractas

sect412 Plantillas

Funciones geneacutericasClases geneacutericas

Aunque las secciones anteriores describen completamente el lenguaje desde una perspectiva formal hemos antildeadido un capiacutetulo adicional (sect413) dedicado a los tecnicismos En eacutel se incluyen algunos consejos y reglas de buena praacutectica para la programacioacuten C++ asiacute como algunos idioms

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

41 Declaraciones

sect1 Sinopsis

Una declaracioacuten es una claacuteusula que introduce nombres en una unidad de compilacioacuten ( 142) o redeclara nombres introducidos por declaraciones previas La norma sentildeala que una declaracioacuten especifica la interpretacioacuten y atributos de estos nombres (como tipo de enlazado y de almacenamiento si es un objeto) asiacute como las condiciones para que una declaracioacuten no sea

tambieacuten una definicioacuten En la paacutegina adjunta se muestra su gramaacutetica ( Gramaacutetica)

Cada una de las introducciones unitarias que puede existir en una declaracioacuten es un declarador (declarator) Asiacute pues un declarador introduce un nombre o redeclara uno

declarado previamente La paacutegina adjunta muestra su gramaacutetica ( Gramaacutetica)

El presente capiacutetulo repasa este importante concepto y otros relacionados tales como objetos clases de almacenamiento tipos aacutembitovisibilidad duracioacuten y enlazado

El aacutembito visibilidad duracioacuten y enlazado son propiedades o caracteriacutesticas 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 definicioacuten de declaracioacuten o la exposicioacuten de su sintaxis

En el epiacutegrafe 4111 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 tambieacuten es dada a conocer mediante una declaracioacuten

411 Entidades

sect1 Presentacioacuten

En relacioacuten con los conceptos que aquiacute nos incumben consideramos que una entidad ( 121) 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 objeto-valor

Un algoritmo con informacioacuten sobre manipulacioacuten de datos Lo denominamos entidad-algoritmo o simplemente algoritmo

Respecto a los objetos-valor una posible clasificacioacuten podriacutea dividirlos en las siguientes categoriacuteas

Agregados

o matrizo estructurao unioacuteno clase unioacuten

Funciones Escalares

o Aritmeacuteticoo Enumeracioacuteno Booleanoo Punteroo Referencia

void

void ( 221) es un tipo especial con un valor muy particular ausencia de valor Los escalares son de caracteriacutesticas tales que su valor no pueden ser descompuestos en partes maacutes pequentildeas

por ejemplo un entero un valor loacutegico (cierto-falso) etc Las funciones ( 44) son principalmente algoritmo ya que estaacuten asociadas a ciertas operaciones (cierta computacioacuten) pero por convencioacuten se les puede asignar un valor es el que devuelven (puede ser void) Por su parte los agregados comparten la caracteriacutestica de que su valor puede ser descompuesto en elementos maacutes simples (escalares)

sect2 El papel de las declaraciones

Haciendo un siacutemil social podriacuteamos decir que las declaraciones son las encargadas de presentar al compilador cualquier entidad que deba existir en el programa Son por tanto el Chambelaacuten de la sociedad C++ Como en el caso de las presentaciones sociales esta presentacioacuten no se reduce a indicar el nombre tambieacuten puede sentildealarse algunas caracteriacutesticas 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

sect3 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 expresioacuten compleja que

represente uniacutevocamente al objeto ( 211 ) Cualquier intento de utilizar una declaracioacuten sin un nombre es un error aunque el nombre no tiene que responder necesariamente a un objeto o funcioacuten Ejemplo

extern int Errorchar Errorchar cptr Ok cptr nombre de punteroclass C Ok C nombre de clasetypedef unsigned int UINT Ok UINT alias para un tipo conocido

Ademaacutes del identificador las declaraciones de funciones pueden incluir ciertos atributos inline ( 4112a) virtual ( 4118a) y explicit ( 4112d1)

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 ( 21 ) Entre otros puede incluir los siguientes char wchar_t bool short int long signed unsigned float double void

Relativos al tipo de almacenamiento Determina el sitio en que se guarda el objeto y su

duracioacuten ( 213 ) 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 disquisicioacuten respecto a si un mismo objeto Por ejemplo una variable puede estar referenciado por dos identificadores distintos (que se refieren a la misma regioacuten de memoria) En la mayoriacutea de lenguajes de programacioacuten esta distincioacuten entre identificador y almacenamiento estaacute perfectamente establecida y suelen proporcionar mecanismos sintaacutecticos para que dos identificadores puedan referirse al mismo almacenamiento

412 Declaraciones y definiciones

sect1 Sinopsis

Utilizando un leacutexico formalista podemos decir que una declaracioacuten es una sentencia que

introduce un nombre en una unidad de compilacioacuten ( 142) daacutendole existencia semaacutentica Esto de la existencia semaacutentica es una forma elegante de decir que a partir de ahiacute el compilador sabe que cosa es (representa) ese nombre La forma de darle existencia semaacutentica a las entidades es declararlos (algo asiacute como presentarlos formalmente en el coacutedigo) Por ejemplo si declaramos una variable x o una funcioacuten func a partir de ahiacute el compilador sabe que x es una variable de tal tipo y que func es una funcioacuten de caracteriacutesticas cuales

El punto importante a resaltar aquiacute es que cada declaracioacuten asocia un nombre con un tipo de dato

lo que en C++ (una sociedad muy clasista 22) es importante ya que el conocimiento del tipo que corresponde a un identificador proporciona al compilador mucha informacioacuten sobre la entidad

representada por este (en muchas ocasiones casi toda la informacioacuten necesaria ) En especial el compilador dispone de una amplia informacioacuten acerca del uso de los tipos baacutesicos que operaciones son permitidas y que significado tienen estas operaciones

No olvidar que una declaracioacuten no hace nada maacutes que esto Es decir no antildeade ninguna otra informacioacuten distinta de relacionar una etiqueta con un tipo Posteriormente cuando esta etiqueta esteacute asociada con una entidad concreta (con una zona de memoria) las operaciones permitidas se

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

que comienza en el punto de la declaracioacuten 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)

Despueacutes del corchete de cierre no se necesita el punto y coma de fin de sentencia

if (statement) punto y coma ilegal else

Nota las llaves sirven tambieacuten en C++ para otros usos distintos de la pura delimitacioacuten de bloques de coacutedigo Por ejemplo en la definicioacuten de estructuras uniones y clases en cuyo caso si puede ser necesaria la inclusioacuten del punto y coma despueacutes de la llave de cierre

sect5 Coma

La coma como puntuador se utiliza para separar los elementos en las listas de paraacutemetros de una funcioacuten

void func(int n float f char ch)

La coma se usa tambieacuten como un operador en las expresiones con coma ( 4105) Es posible mezclar los dos usos (separador en lista de paraacutemetros y operador) pero deben usarse pareacutentesis para distinguirlos

sect6 Punto y coma

El punto y coma es el signo de fin de sentencia Cualquier expresioacuten legal C++ terminada por un punto y coma (incluyendo la expresioacuten vaciacutea - un punto y coma aislado-) es interpretado como una

sentencia conocidas como sentencia-expresioacuten ( 410) La expresioacuten se evaluacutea y el resultado se descarta si no tiene efectos colaterales C++ la ignora

a + b evaluacutea a + b descarta el resultado++a efecto lateral en a se descarta el valor ++a expresioacuten vaciacutea = sentencia nula

El punto y coma se usa a veces para crear sentencias nulas

for (i = 0 i lt n i++) sentencia nula (hacer nada)

sect7 Dos puntos

Los dos puntos se utilizan para sentildealar sentencias etiquetadas ( 4101)

comienzo x=0 comienzo es la etiquetagoto comienzo

sect8 Puntos suspensivos

Los puntos suspensivos tambieacuten 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 nuacutemero variable de argumentos o pueden ser de tipo variable ( 441) Por ejemplo

void func(int n char ch)

Este prototipo de funcioacuten declara que func estaacute definida de modo que debe ser llamada con al

menos dos argumentos un int y un char Ademaacutes puede tener un cierto nuacutemero de argumentos adicionales (puede omitirse la coma antes de la elipsis)

Se utiliza tambieacuten para indicar que un manejador de excepciones (handler) puede capturar una

excepcioacuten de cualquier tipo ( 162) Ejemplo

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

Nota como podeacuteis ver en ocasiones mi uso particular en los ejemplos de los tres puntos es para indicar cualquier nuacutemero de sentencias Espero que no sea motivo de confusioacuten Desde luego en el caso anterior seriacutea maacutes correcta la notacioacuten

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

sect9 Asterisco

El asterisco puede ser utilizado en C++ de tres formas como una declaracioacuten de tipo de variable

(variable de puntero 42 ) como operador de indireccioacuten (tambieacuten llamado operador

de dereferencia 4911a) y como operador de multiplicacioacuten

Ejemplos

char char_ptr declara puntero a caraacutecterx = int_ptr operador de indireccioacutenl = 2 314 r operador multiplicacioacuten

sect10 Signo igual =

El signo igual = separa la declaracioacuten de variables de las listas de inicializacioacuten

char array[5] = 1 2 3 4 5

Recordemos que al contrario que en C donde las declaraciones no pueden estar precedidas por ninguacuten coacutedigo deben ir al principio en C++ las declaraciones de cualquier tipo pueden aparecer en cualquier punto del coacutedigo (con algunas restricciones)

En la lista de argumentos de una funcioacuten el signo igual indica el valor por defecto para un paraacutemetro

int f(int i = 0) el valor por defecto de k es cero

El signo igual es tambieacuten utilizado como operador de asignacioacuten ( 492) Ejemplo

x = yz += 5

sect11 Almohadilla

Si la almohadilla aparecen en el primer caraacutecter (distinto de espacio en blanco) de una liacutenea

sentildeala directivas de preproceso ( 4910) En este caso es un operador especiacutefico de la fase

de preproceso del coacutedigo fuente Significa una opcioacuten del preprocesador ( 14) que no tiene porqueacute estar asociada necesariamente a generacioacuten de coacutedigo Las directivas se situacutean generalmente al comienzo del programa aunque legalmente pueden aparecer en cualquier punto

Ejemplos de directivas de preproceso

(null directive)define NULO 0include ltstdiohgt

4 Estructura del lenguaje

sect1 Sinopsis

Esta parte proporciona una definicioacuten formal del lenguaje C++ describiendo las formas en que

pueden agruparse correctamente los tokens ( 32) palabras que constituyen el lenguaje entendible por el compilador para formar declaraciones expresiones y otras unidades significativas Para su anaacutelisis lo hemos descompuesto en 13 grupos seguacuten la clasificacioacuten que sigue

sect41 Declaraciones

ObjetosReferencias amp definicionesDefinicioacuten provisionalAacutembitoVisibilidadDuracioacutenUnidad de compilacioacutenEnlazado

Sintaxis de declaraciones

Conversiones aritmeacuteticasInicializacioacutenEspecificadores de clase de almacenamientoModificadores auxiliaresModificadores de funcioacuten

sect42 Punteros

Puntero a objetoDeclaracioacuten de punterosAritmeacutetica de punterosReferenciasPuntero a funcioacuten

sect43 Matrices

Declaracioacuten de matricesMatrices alfanumeacutericasMatrices de punterosMatrices de matrices

sect44 Funciones

DeclaracioacutenDefinicioacutenArgumentos formales y actualesLlamada y conversioacuten de argumentosValores devueltos

sect45 Estructuras

Declaracioacuten de estructurasInicializacioacutenOperaciones permitidasAcceso a miembrosEstructuras y funcionesMatrices de estructurasPunteros a estructurasEstructuras auto-referenciadas

sect46 Campos de Bits

sect47 Uniones

sect48 Enumeraciones

Expresiones

Asociatividad y precedencia de operadoresOrden de evaluacioacutenErrores y desbordamientosExpresiones con coma

sect49 Operadores

AritmeacuteticosAsignacioacutenManejo de BitsOperador ComaCondicionalOp de igualdadOp LoacutegicosModelado de tiposOp de PreprocesoOp de punteroRelacionalessizeoftypeidOp primariosOp antildeadidosOp UnitariosSobrecarga de OperadoresOperador Operador newOperador delete

sect410 Sentencias

Sentencias de etiqueta case defaultSentencias de seleccioacuten if hellip else else if switchSentencias de iteracioacuten while dowhile forSentencias de salto break continue goto return

sect411 Clases

CreacioacutenDeclaracioacutenNombres de ClasesAacutembito de nombresInstanciado de Clasesthis (palabra reservada)Miembros estaacuteticosClases polimoacuterficasFunciones virtualesFunciones dinaacutemicasClases abstractas

sect412 Plantillas

Funciones geneacutericasClases geneacutericas

Aunque las secciones anteriores describen completamente el lenguaje desde una perspectiva formal hemos antildeadido un capiacutetulo adicional (sect413) dedicado a los tecnicismos En eacutel se incluyen algunos consejos y reglas de buena praacutectica para la programacioacuten C++ asiacute como algunos idioms

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

41 Declaraciones

sect1 Sinopsis

Una declaracioacuten es una claacuteusula que introduce nombres en una unidad de compilacioacuten ( 142) o redeclara nombres introducidos por declaraciones previas La norma sentildeala que una declaracioacuten especifica la interpretacioacuten y atributos de estos nombres (como tipo de enlazado y de almacenamiento si es un objeto) asiacute como las condiciones para que una declaracioacuten no sea

tambieacuten una definicioacuten En la paacutegina adjunta se muestra su gramaacutetica ( Gramaacutetica)

Cada una de las introducciones unitarias que puede existir en una declaracioacuten es un declarador (declarator) Asiacute pues un declarador introduce un nombre o redeclara uno

declarado previamente La paacutegina adjunta muestra su gramaacutetica ( Gramaacutetica)

El presente capiacutetulo repasa este importante concepto y otros relacionados tales como objetos clases de almacenamiento tipos aacutembitovisibilidad duracioacuten y enlazado

El aacutembito visibilidad duracioacuten y enlazado son propiedades o caracteriacutesticas 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 definicioacuten de declaracioacuten o la exposicioacuten de su sintaxis

En el epiacutegrafe 4111 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 tambieacuten es dada a conocer mediante una declaracioacuten

411 Entidades

sect1 Presentacioacuten

En relacioacuten con los conceptos que aquiacute nos incumben consideramos que una entidad ( 121) 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 objeto-valor

Un algoritmo con informacioacuten sobre manipulacioacuten de datos Lo denominamos entidad-algoritmo o simplemente algoritmo

Respecto a los objetos-valor una posible clasificacioacuten podriacutea dividirlos en las siguientes categoriacuteas

Agregados

o matrizo estructurao unioacuteno clase unioacuten

Funciones Escalares

o Aritmeacuteticoo Enumeracioacuteno Booleanoo Punteroo Referencia

void

void ( 221) es un tipo especial con un valor muy particular ausencia de valor Los escalares son de caracteriacutesticas tales que su valor no pueden ser descompuestos en partes maacutes pequentildeas

por ejemplo un entero un valor loacutegico (cierto-falso) etc Las funciones ( 44) son principalmente algoritmo ya que estaacuten asociadas a ciertas operaciones (cierta computacioacuten) pero por convencioacuten se les puede asignar un valor es el que devuelven (puede ser void) Por su parte los agregados comparten la caracteriacutestica de que su valor puede ser descompuesto en elementos maacutes simples (escalares)

sect2 El papel de las declaraciones

Haciendo un siacutemil social podriacuteamos decir que las declaraciones son las encargadas de presentar al compilador cualquier entidad que deba existir en el programa Son por tanto el Chambelaacuten de la sociedad C++ Como en el caso de las presentaciones sociales esta presentacioacuten no se reduce a indicar el nombre tambieacuten puede sentildealarse algunas caracteriacutesticas 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

sect3 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 expresioacuten compleja que

represente uniacutevocamente al objeto ( 211 ) Cualquier intento de utilizar una declaracioacuten sin un nombre es un error aunque el nombre no tiene que responder necesariamente a un objeto o funcioacuten Ejemplo

extern int Errorchar Errorchar cptr Ok cptr nombre de punteroclass C Ok C nombre de clasetypedef unsigned int UINT Ok UINT alias para un tipo conocido

Ademaacutes del identificador las declaraciones de funciones pueden incluir ciertos atributos inline ( 4112a) virtual ( 4118a) y explicit ( 4112d1)

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 ( 21 ) Entre otros puede incluir los siguientes char wchar_t bool short int long signed unsigned float double void

Relativos al tipo de almacenamiento Determina el sitio en que se guarda el objeto y su

duracioacuten ( 213 ) 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 disquisicioacuten respecto a si un mismo objeto Por ejemplo una variable puede estar referenciado por dos identificadores distintos (que se refieren a la misma regioacuten de memoria) En la mayoriacutea de lenguajes de programacioacuten esta distincioacuten entre identificador y almacenamiento estaacute perfectamente establecida y suelen proporcionar mecanismos sintaacutecticos para que dos identificadores puedan referirse al mismo almacenamiento

412 Declaraciones y definiciones

sect1 Sinopsis

Utilizando un leacutexico formalista podemos decir que una declaracioacuten es una sentencia que

introduce un nombre en una unidad de compilacioacuten ( 142) daacutendole existencia semaacutentica Esto de la existencia semaacutentica es una forma elegante de decir que a partir de ahiacute el compilador sabe que cosa es (representa) ese nombre La forma de darle existencia semaacutentica a las entidades es declararlos (algo asiacute como presentarlos formalmente en el coacutedigo) Por ejemplo si declaramos una variable x o una funcioacuten func a partir de ahiacute el compilador sabe que x es una variable de tal tipo y que func es una funcioacuten de caracteriacutesticas cuales

El punto importante a resaltar aquiacute es que cada declaracioacuten asocia un nombre con un tipo de dato

lo que en C++ (una sociedad muy clasista 22) es importante ya que el conocimiento del tipo que corresponde a un identificador proporciona al compilador mucha informacioacuten sobre la entidad

representada por este (en muchas ocasiones casi toda la informacioacuten necesaria ) En especial el compilador dispone de una amplia informacioacuten acerca del uso de los tipos baacutesicos que operaciones son permitidas y que significado tienen estas operaciones

No olvidar que una declaracioacuten no hace nada maacutes que esto Es decir no antildeade ninguna otra informacioacuten distinta de relacionar una etiqueta con un tipo Posteriormente cuando esta etiqueta esteacute asociada con una entidad concreta (con una zona de memoria) las operaciones permitidas se

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

comienzo x=0 comienzo es la etiquetagoto comienzo

sect8 Puntos suspensivos

Los puntos suspensivos tambieacuten 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 nuacutemero variable de argumentos o pueden ser de tipo variable ( 441) Por ejemplo

void func(int n char ch)

Este prototipo de funcioacuten declara que func estaacute definida de modo que debe ser llamada con al

menos dos argumentos un int y un char Ademaacutes puede tener un cierto nuacutemero de argumentos adicionales (puede omitirse la coma antes de la elipsis)

Se utiliza tambieacuten para indicar que un manejador de excepciones (handler) puede capturar una

excepcioacuten de cualquier tipo ( 162) Ejemplo

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

Nota como podeacuteis ver en ocasiones mi uso particular en los ejemplos de los tres puntos es para indicar cualquier nuacutemero de sentencias Espero que no sea motivo de confusioacuten Desde luego en el caso anterior seriacutea maacutes correcta la notacioacuten

try bloque-intento catch () captura cualquier excepcioacuten cout ltlt Se ha producido una excepcioacuten ltlt endl

sect9 Asterisco

El asterisco puede ser utilizado en C++ de tres formas como una declaracioacuten de tipo de variable

(variable de puntero 42 ) como operador de indireccioacuten (tambieacuten llamado operador

de dereferencia 4911a) y como operador de multiplicacioacuten

Ejemplos

char char_ptr declara puntero a caraacutecterx = int_ptr operador de indireccioacutenl = 2 314 r operador multiplicacioacuten

sect10 Signo igual =

El signo igual = separa la declaracioacuten de variables de las listas de inicializacioacuten

char array[5] = 1 2 3 4 5

Recordemos que al contrario que en C donde las declaraciones no pueden estar precedidas por ninguacuten coacutedigo deben ir al principio en C++ las declaraciones de cualquier tipo pueden aparecer en cualquier punto del coacutedigo (con algunas restricciones)

En la lista de argumentos de una funcioacuten el signo igual indica el valor por defecto para un paraacutemetro

int f(int i = 0) el valor por defecto de k es cero

El signo igual es tambieacuten utilizado como operador de asignacioacuten ( 492) Ejemplo

x = yz += 5

sect11 Almohadilla

Si la almohadilla aparecen en el primer caraacutecter (distinto de espacio en blanco) de una liacutenea

sentildeala directivas de preproceso ( 4910) En este caso es un operador especiacutefico de la fase

de preproceso del coacutedigo fuente Significa una opcioacuten del preprocesador ( 14) que no tiene porqueacute estar asociada necesariamente a generacioacuten de coacutedigo Las directivas se situacutean generalmente al comienzo del programa aunque legalmente pueden aparecer en cualquier punto

Ejemplos de directivas de preproceso

(null directive)define NULO 0include ltstdiohgt

4 Estructura del lenguaje

sect1 Sinopsis

Esta parte proporciona una definicioacuten formal del lenguaje C++ describiendo las formas en que

pueden agruparse correctamente los tokens ( 32) palabras que constituyen el lenguaje entendible por el compilador para formar declaraciones expresiones y otras unidades significativas Para su anaacutelisis lo hemos descompuesto en 13 grupos seguacuten la clasificacioacuten que sigue

sect41 Declaraciones

ObjetosReferencias amp definicionesDefinicioacuten provisionalAacutembitoVisibilidadDuracioacutenUnidad de compilacioacutenEnlazado

Sintaxis de declaraciones

Conversiones aritmeacuteticasInicializacioacutenEspecificadores de clase de almacenamientoModificadores auxiliaresModificadores de funcioacuten

sect42 Punteros

Puntero a objetoDeclaracioacuten de punterosAritmeacutetica de punterosReferenciasPuntero a funcioacuten

sect43 Matrices

Declaracioacuten de matricesMatrices alfanumeacutericasMatrices de punterosMatrices de matrices

sect44 Funciones

DeclaracioacutenDefinicioacutenArgumentos formales y actualesLlamada y conversioacuten de argumentosValores devueltos

sect45 Estructuras

Declaracioacuten de estructurasInicializacioacutenOperaciones permitidasAcceso a miembrosEstructuras y funcionesMatrices de estructurasPunteros a estructurasEstructuras auto-referenciadas

sect46 Campos de Bits

sect47 Uniones

sect48 Enumeraciones

Expresiones

Asociatividad y precedencia de operadoresOrden de evaluacioacutenErrores y desbordamientosExpresiones con coma

sect49 Operadores

AritmeacuteticosAsignacioacutenManejo de BitsOperador ComaCondicionalOp de igualdadOp LoacutegicosModelado de tiposOp de PreprocesoOp de punteroRelacionalessizeoftypeidOp primariosOp antildeadidosOp UnitariosSobrecarga de OperadoresOperador Operador newOperador delete

sect410 Sentencias

Sentencias de etiqueta case defaultSentencias de seleccioacuten if hellip else else if switchSentencias de iteracioacuten while dowhile forSentencias de salto break continue goto return

sect411 Clases

CreacioacutenDeclaracioacutenNombres de ClasesAacutembito de nombresInstanciado de Clasesthis (palabra reservada)Miembros estaacuteticosClases polimoacuterficasFunciones virtualesFunciones dinaacutemicasClases abstractas

sect412 Plantillas

Funciones geneacutericasClases geneacutericas

Aunque las secciones anteriores describen completamente el lenguaje desde una perspectiva formal hemos antildeadido un capiacutetulo adicional (sect413) dedicado a los tecnicismos En eacutel se incluyen algunos consejos y reglas de buena praacutectica para la programacioacuten C++ asiacute como algunos idioms

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

41 Declaraciones

sect1 Sinopsis

Una declaracioacuten es una claacuteusula que introduce nombres en una unidad de compilacioacuten ( 142) o redeclara nombres introducidos por declaraciones previas La norma sentildeala que una declaracioacuten especifica la interpretacioacuten y atributos de estos nombres (como tipo de enlazado y de almacenamiento si es un objeto) asiacute como las condiciones para que una declaracioacuten no sea

tambieacuten una definicioacuten En la paacutegina adjunta se muestra su gramaacutetica ( Gramaacutetica)

Cada una de las introducciones unitarias que puede existir en una declaracioacuten es un declarador (declarator) Asiacute pues un declarador introduce un nombre o redeclara uno

declarado previamente La paacutegina adjunta muestra su gramaacutetica ( Gramaacutetica)

El presente capiacutetulo repasa este importante concepto y otros relacionados tales como objetos clases de almacenamiento tipos aacutembitovisibilidad duracioacuten y enlazado

El aacutembito visibilidad duracioacuten y enlazado son propiedades o caracteriacutesticas 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 definicioacuten de declaracioacuten o la exposicioacuten de su sintaxis

En el epiacutegrafe 4111 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 tambieacuten es dada a conocer mediante una declaracioacuten

411 Entidades

sect1 Presentacioacuten

En relacioacuten con los conceptos que aquiacute nos incumben consideramos que una entidad ( 121) 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 objeto-valor

Un algoritmo con informacioacuten sobre manipulacioacuten de datos Lo denominamos entidad-algoritmo o simplemente algoritmo

Respecto a los objetos-valor una posible clasificacioacuten podriacutea dividirlos en las siguientes categoriacuteas

Agregados

o matrizo estructurao unioacuteno clase unioacuten

Funciones Escalares

o Aritmeacuteticoo Enumeracioacuteno Booleanoo Punteroo Referencia

void

void ( 221) es un tipo especial con un valor muy particular ausencia de valor Los escalares son de caracteriacutesticas tales que su valor no pueden ser descompuestos en partes maacutes pequentildeas

por ejemplo un entero un valor loacutegico (cierto-falso) etc Las funciones ( 44) son principalmente algoritmo ya que estaacuten asociadas a ciertas operaciones (cierta computacioacuten) pero por convencioacuten se les puede asignar un valor es el que devuelven (puede ser void) Por su parte los agregados comparten la caracteriacutestica de que su valor puede ser descompuesto en elementos maacutes simples (escalares)

sect2 El papel de las declaraciones

Haciendo un siacutemil social podriacuteamos decir que las declaraciones son las encargadas de presentar al compilador cualquier entidad que deba existir en el programa Son por tanto el Chambelaacuten de la sociedad C++ Como en el caso de las presentaciones sociales esta presentacioacuten no se reduce a indicar el nombre tambieacuten puede sentildealarse algunas caracteriacutesticas 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

sect3 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 expresioacuten compleja que

represente uniacutevocamente al objeto ( 211 ) Cualquier intento de utilizar una declaracioacuten sin un nombre es un error aunque el nombre no tiene que responder necesariamente a un objeto o funcioacuten Ejemplo

extern int Errorchar Errorchar cptr Ok cptr nombre de punteroclass C Ok C nombre de clasetypedef unsigned int UINT Ok UINT alias para un tipo conocido

Ademaacutes del identificador las declaraciones de funciones pueden incluir ciertos atributos inline ( 4112a) virtual ( 4118a) y explicit ( 4112d1)

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 ( 21 ) Entre otros puede incluir los siguientes char wchar_t bool short int long signed unsigned float double void

Relativos al tipo de almacenamiento Determina el sitio en que se guarda el objeto y su

duracioacuten ( 213 ) 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 disquisicioacuten respecto a si un mismo objeto Por ejemplo una variable puede estar referenciado por dos identificadores distintos (que se refieren a la misma regioacuten de memoria) En la mayoriacutea de lenguajes de programacioacuten esta distincioacuten entre identificador y almacenamiento estaacute perfectamente establecida y suelen proporcionar mecanismos sintaacutecticos para que dos identificadores puedan referirse al mismo almacenamiento

412 Declaraciones y definiciones

sect1 Sinopsis

Utilizando un leacutexico formalista podemos decir que una declaracioacuten es una sentencia que

introduce un nombre en una unidad de compilacioacuten ( 142) daacutendole existencia semaacutentica Esto de la existencia semaacutentica es una forma elegante de decir que a partir de ahiacute el compilador sabe que cosa es (representa) ese nombre La forma de darle existencia semaacutentica a las entidades es declararlos (algo asiacute como presentarlos formalmente en el coacutedigo) Por ejemplo si declaramos una variable x o una funcioacuten func a partir de ahiacute el compilador sabe que x es una variable de tal tipo y que func es una funcioacuten de caracteriacutesticas cuales

El punto importante a resaltar aquiacute es que cada declaracioacuten asocia un nombre con un tipo de dato

lo que en C++ (una sociedad muy clasista 22) es importante ya que el conocimiento del tipo que corresponde a un identificador proporciona al compilador mucha informacioacuten sobre la entidad

representada por este (en muchas ocasiones casi toda la informacioacuten necesaria ) En especial el compilador dispone de una amplia informacioacuten acerca del uso de los tipos baacutesicos que operaciones son permitidas y que significado tienen estas operaciones

No olvidar que una declaracioacuten no hace nada maacutes que esto Es decir no antildeade ninguna otra informacioacuten distinta de relacionar una etiqueta con un tipo Posteriormente cuando esta etiqueta esteacute asociada con una entidad concreta (con una zona de memoria) las operaciones permitidas se

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

char char_ptr declara puntero a caraacutecterx = int_ptr operador de indireccioacutenl = 2 314 r operador multiplicacioacuten

sect10 Signo igual =

El signo igual = separa la declaracioacuten de variables de las listas de inicializacioacuten

char array[5] = 1 2 3 4 5

Recordemos que al contrario que en C donde las declaraciones no pueden estar precedidas por ninguacuten coacutedigo deben ir al principio en C++ las declaraciones de cualquier tipo pueden aparecer en cualquier punto del coacutedigo (con algunas restricciones)

En la lista de argumentos de una funcioacuten el signo igual indica el valor por defecto para un paraacutemetro

int f(int i = 0) el valor por defecto de k es cero

El signo igual es tambieacuten utilizado como operador de asignacioacuten ( 492) Ejemplo

x = yz += 5

sect11 Almohadilla

Si la almohadilla aparecen en el primer caraacutecter (distinto de espacio en blanco) de una liacutenea

sentildeala directivas de preproceso ( 4910) En este caso es un operador especiacutefico de la fase

de preproceso del coacutedigo fuente Significa una opcioacuten del preprocesador ( 14) que no tiene porqueacute estar asociada necesariamente a generacioacuten de coacutedigo Las directivas se situacutean generalmente al comienzo del programa aunque legalmente pueden aparecer en cualquier punto

Ejemplos de directivas de preproceso

(null directive)define NULO 0include ltstdiohgt

4 Estructura del lenguaje

sect1 Sinopsis

Esta parte proporciona una definicioacuten formal del lenguaje C++ describiendo las formas en que

pueden agruparse correctamente los tokens ( 32) palabras que constituyen el lenguaje entendible por el compilador para formar declaraciones expresiones y otras unidades significativas Para su anaacutelisis lo hemos descompuesto en 13 grupos seguacuten la clasificacioacuten que sigue

sect41 Declaraciones

ObjetosReferencias amp definicionesDefinicioacuten provisionalAacutembitoVisibilidadDuracioacutenUnidad de compilacioacutenEnlazado

Sintaxis de declaraciones

Conversiones aritmeacuteticasInicializacioacutenEspecificadores de clase de almacenamientoModificadores auxiliaresModificadores de funcioacuten

sect42 Punteros

Puntero a objetoDeclaracioacuten de punterosAritmeacutetica de punterosReferenciasPuntero a funcioacuten

sect43 Matrices

Declaracioacuten de matricesMatrices alfanumeacutericasMatrices de punterosMatrices de matrices

sect44 Funciones

DeclaracioacutenDefinicioacutenArgumentos formales y actualesLlamada y conversioacuten de argumentosValores devueltos

sect45 Estructuras

Declaracioacuten de estructurasInicializacioacutenOperaciones permitidasAcceso a miembrosEstructuras y funcionesMatrices de estructurasPunteros a estructurasEstructuras auto-referenciadas

sect46 Campos de Bits

sect47 Uniones

sect48 Enumeraciones

Expresiones

Asociatividad y precedencia de operadoresOrden de evaluacioacutenErrores y desbordamientosExpresiones con coma

sect49 Operadores

AritmeacuteticosAsignacioacutenManejo de BitsOperador ComaCondicionalOp de igualdadOp LoacutegicosModelado de tiposOp de PreprocesoOp de punteroRelacionalessizeoftypeidOp primariosOp antildeadidosOp UnitariosSobrecarga de OperadoresOperador Operador newOperador delete

sect410 Sentencias

Sentencias de etiqueta case defaultSentencias de seleccioacuten if hellip else else if switchSentencias de iteracioacuten while dowhile forSentencias de salto break continue goto return

sect411 Clases

CreacioacutenDeclaracioacutenNombres de ClasesAacutembito de nombresInstanciado de Clasesthis (palabra reservada)Miembros estaacuteticosClases polimoacuterficasFunciones virtualesFunciones dinaacutemicasClases abstractas

sect412 Plantillas

Funciones geneacutericasClases geneacutericas

Aunque las secciones anteriores describen completamente el lenguaje desde una perspectiva formal hemos antildeadido un capiacutetulo adicional (sect413) dedicado a los tecnicismos En eacutel se incluyen algunos consejos y reglas de buena praacutectica para la programacioacuten C++ asiacute como algunos idioms

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

41 Declaraciones

sect1 Sinopsis

Una declaracioacuten es una claacuteusula que introduce nombres en una unidad de compilacioacuten ( 142) o redeclara nombres introducidos por declaraciones previas La norma sentildeala que una declaracioacuten especifica la interpretacioacuten y atributos de estos nombres (como tipo de enlazado y de almacenamiento si es un objeto) asiacute como las condiciones para que una declaracioacuten no sea

tambieacuten una definicioacuten En la paacutegina adjunta se muestra su gramaacutetica ( Gramaacutetica)

Cada una de las introducciones unitarias que puede existir en una declaracioacuten es un declarador (declarator) Asiacute pues un declarador introduce un nombre o redeclara uno

declarado previamente La paacutegina adjunta muestra su gramaacutetica ( Gramaacutetica)

El presente capiacutetulo repasa este importante concepto y otros relacionados tales como objetos clases de almacenamiento tipos aacutembitovisibilidad duracioacuten y enlazado

El aacutembito visibilidad duracioacuten y enlazado son propiedades o caracteriacutesticas 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 definicioacuten de declaracioacuten o la exposicioacuten de su sintaxis

En el epiacutegrafe 4111 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 tambieacuten es dada a conocer mediante una declaracioacuten

411 Entidades

sect1 Presentacioacuten

En relacioacuten con los conceptos que aquiacute nos incumben consideramos que una entidad ( 121) 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 objeto-valor

Un algoritmo con informacioacuten sobre manipulacioacuten de datos Lo denominamos entidad-algoritmo o simplemente algoritmo

Respecto a los objetos-valor una posible clasificacioacuten podriacutea dividirlos en las siguientes categoriacuteas

Agregados

o matrizo estructurao unioacuteno clase unioacuten

Funciones Escalares

o Aritmeacuteticoo Enumeracioacuteno Booleanoo Punteroo Referencia

void

void ( 221) es un tipo especial con un valor muy particular ausencia de valor Los escalares son de caracteriacutesticas tales que su valor no pueden ser descompuestos en partes maacutes pequentildeas

por ejemplo un entero un valor loacutegico (cierto-falso) etc Las funciones ( 44) son principalmente algoritmo ya que estaacuten asociadas a ciertas operaciones (cierta computacioacuten) pero por convencioacuten se les puede asignar un valor es el que devuelven (puede ser void) Por su parte los agregados comparten la caracteriacutestica de que su valor puede ser descompuesto en elementos maacutes simples (escalares)

sect2 El papel de las declaraciones

Haciendo un siacutemil social podriacuteamos decir que las declaraciones son las encargadas de presentar al compilador cualquier entidad que deba existir en el programa Son por tanto el Chambelaacuten de la sociedad C++ Como en el caso de las presentaciones sociales esta presentacioacuten no se reduce a indicar el nombre tambieacuten puede sentildealarse algunas caracteriacutesticas 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

sect3 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 expresioacuten compleja que

represente uniacutevocamente al objeto ( 211 ) Cualquier intento de utilizar una declaracioacuten sin un nombre es un error aunque el nombre no tiene que responder necesariamente a un objeto o funcioacuten Ejemplo

extern int Errorchar Errorchar cptr Ok cptr nombre de punteroclass C Ok C nombre de clasetypedef unsigned int UINT Ok UINT alias para un tipo conocido

Ademaacutes del identificador las declaraciones de funciones pueden incluir ciertos atributos inline ( 4112a) virtual ( 4118a) y explicit ( 4112d1)

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 ( 21 ) Entre otros puede incluir los siguientes char wchar_t bool short int long signed unsigned float double void

Relativos al tipo de almacenamiento Determina el sitio en que se guarda el objeto y su

duracioacuten ( 213 ) 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 disquisicioacuten respecto a si un mismo objeto Por ejemplo una variable puede estar referenciado por dos identificadores distintos (que se refieren a la misma regioacuten de memoria) En la mayoriacutea de lenguajes de programacioacuten esta distincioacuten entre identificador y almacenamiento estaacute perfectamente establecida y suelen proporcionar mecanismos sintaacutecticos para que dos identificadores puedan referirse al mismo almacenamiento

412 Declaraciones y definiciones

sect1 Sinopsis

Utilizando un leacutexico formalista podemos decir que una declaracioacuten es una sentencia que

introduce un nombre en una unidad de compilacioacuten ( 142) daacutendole existencia semaacutentica Esto de la existencia semaacutentica es una forma elegante de decir que a partir de ahiacute el compilador sabe que cosa es (representa) ese nombre La forma de darle existencia semaacutentica a las entidades es declararlos (algo asiacute como presentarlos formalmente en el coacutedigo) Por ejemplo si declaramos una variable x o una funcioacuten func a partir de ahiacute el compilador sabe que x es una variable de tal tipo y que func es una funcioacuten de caracteriacutesticas cuales

El punto importante a resaltar aquiacute es que cada declaracioacuten asocia un nombre con un tipo de dato

lo que en C++ (una sociedad muy clasista 22) es importante ya que el conocimiento del tipo que corresponde a un identificador proporciona al compilador mucha informacioacuten sobre la entidad

representada por este (en muchas ocasiones casi toda la informacioacuten necesaria ) En especial el compilador dispone de una amplia informacioacuten acerca del uso de los tipos baacutesicos que operaciones son permitidas y que significado tienen estas operaciones

No olvidar que una declaracioacuten no hace nada maacutes que esto Es decir no antildeade ninguna otra informacioacuten distinta de relacionar una etiqueta con un tipo Posteriormente cuando esta etiqueta esteacute asociada con una entidad concreta (con una zona de memoria) las operaciones permitidas se

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

Esta parte proporciona una definicioacuten formal del lenguaje C++ describiendo las formas en que

pueden agruparse correctamente los tokens ( 32) palabras que constituyen el lenguaje entendible por el compilador para formar declaraciones expresiones y otras unidades significativas Para su anaacutelisis lo hemos descompuesto en 13 grupos seguacuten la clasificacioacuten que sigue

sect41 Declaraciones

ObjetosReferencias amp definicionesDefinicioacuten provisionalAacutembitoVisibilidadDuracioacutenUnidad de compilacioacutenEnlazado

Sintaxis de declaraciones

Conversiones aritmeacuteticasInicializacioacutenEspecificadores de clase de almacenamientoModificadores auxiliaresModificadores de funcioacuten

sect42 Punteros

Puntero a objetoDeclaracioacuten de punterosAritmeacutetica de punterosReferenciasPuntero a funcioacuten

sect43 Matrices

Declaracioacuten de matricesMatrices alfanumeacutericasMatrices de punterosMatrices de matrices

sect44 Funciones

DeclaracioacutenDefinicioacutenArgumentos formales y actualesLlamada y conversioacuten de argumentosValores devueltos

sect45 Estructuras

Declaracioacuten de estructurasInicializacioacutenOperaciones permitidasAcceso a miembrosEstructuras y funcionesMatrices de estructurasPunteros a estructurasEstructuras auto-referenciadas

sect46 Campos de Bits

sect47 Uniones

sect48 Enumeraciones

Expresiones

Asociatividad y precedencia de operadoresOrden de evaluacioacutenErrores y desbordamientosExpresiones con coma

sect49 Operadores

AritmeacuteticosAsignacioacutenManejo de BitsOperador ComaCondicionalOp de igualdadOp LoacutegicosModelado de tiposOp de PreprocesoOp de punteroRelacionalessizeoftypeidOp primariosOp antildeadidosOp UnitariosSobrecarga de OperadoresOperador Operador newOperador delete

sect410 Sentencias

Sentencias de etiqueta case defaultSentencias de seleccioacuten if hellip else else if switchSentencias de iteracioacuten while dowhile forSentencias de salto break continue goto return

sect411 Clases

CreacioacutenDeclaracioacutenNombres de ClasesAacutembito de nombresInstanciado de Clasesthis (palabra reservada)Miembros estaacuteticosClases polimoacuterficasFunciones virtualesFunciones dinaacutemicasClases abstractas

sect412 Plantillas

Funciones geneacutericasClases geneacutericas

Aunque las secciones anteriores describen completamente el lenguaje desde una perspectiva formal hemos antildeadido un capiacutetulo adicional (sect413) dedicado a los tecnicismos En eacutel se incluyen algunos consejos y reglas de buena praacutectica para la programacioacuten C++ asiacute como algunos idioms

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

41 Declaraciones

sect1 Sinopsis

Una declaracioacuten es una claacuteusula que introduce nombres en una unidad de compilacioacuten ( 142) o redeclara nombres introducidos por declaraciones previas La norma sentildeala que una declaracioacuten especifica la interpretacioacuten y atributos de estos nombres (como tipo de enlazado y de almacenamiento si es un objeto) asiacute como las condiciones para que una declaracioacuten no sea

tambieacuten una definicioacuten En la paacutegina adjunta se muestra su gramaacutetica ( Gramaacutetica)

Cada una de las introducciones unitarias que puede existir en una declaracioacuten es un declarador (declarator) Asiacute pues un declarador introduce un nombre o redeclara uno

declarado previamente La paacutegina adjunta muestra su gramaacutetica ( Gramaacutetica)

El presente capiacutetulo repasa este importante concepto y otros relacionados tales como objetos clases de almacenamiento tipos aacutembitovisibilidad duracioacuten y enlazado

El aacutembito visibilidad duracioacuten y enlazado son propiedades o caracteriacutesticas 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 definicioacuten de declaracioacuten o la exposicioacuten de su sintaxis

En el epiacutegrafe 4111 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 tambieacuten es dada a conocer mediante una declaracioacuten

411 Entidades

sect1 Presentacioacuten

En relacioacuten con los conceptos que aquiacute nos incumben consideramos que una entidad ( 121) 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 objeto-valor

Un algoritmo con informacioacuten sobre manipulacioacuten de datos Lo denominamos entidad-algoritmo o simplemente algoritmo

Respecto a los objetos-valor una posible clasificacioacuten podriacutea dividirlos en las siguientes categoriacuteas

Agregados

o matrizo estructurao unioacuteno clase unioacuten

Funciones Escalares

o Aritmeacuteticoo Enumeracioacuteno Booleanoo Punteroo Referencia

void

void ( 221) es un tipo especial con un valor muy particular ausencia de valor Los escalares son de caracteriacutesticas tales que su valor no pueden ser descompuestos en partes maacutes pequentildeas

por ejemplo un entero un valor loacutegico (cierto-falso) etc Las funciones ( 44) son principalmente algoritmo ya que estaacuten asociadas a ciertas operaciones (cierta computacioacuten) pero por convencioacuten se les puede asignar un valor es el que devuelven (puede ser void) Por su parte los agregados comparten la caracteriacutestica de que su valor puede ser descompuesto en elementos maacutes simples (escalares)

sect2 El papel de las declaraciones

Haciendo un siacutemil social podriacuteamos decir que las declaraciones son las encargadas de presentar al compilador cualquier entidad que deba existir en el programa Son por tanto el Chambelaacuten de la sociedad C++ Como en el caso de las presentaciones sociales esta presentacioacuten no se reduce a indicar el nombre tambieacuten puede sentildealarse algunas caracteriacutesticas 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

sect3 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 expresioacuten compleja que

represente uniacutevocamente al objeto ( 211 ) Cualquier intento de utilizar una declaracioacuten sin un nombre es un error aunque el nombre no tiene que responder necesariamente a un objeto o funcioacuten Ejemplo

extern int Errorchar Errorchar cptr Ok cptr nombre de punteroclass C Ok C nombre de clasetypedef unsigned int UINT Ok UINT alias para un tipo conocido

Ademaacutes del identificador las declaraciones de funciones pueden incluir ciertos atributos inline ( 4112a) virtual ( 4118a) y explicit ( 4112d1)

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 ( 21 ) Entre otros puede incluir los siguientes char wchar_t bool short int long signed unsigned float double void

Relativos al tipo de almacenamiento Determina el sitio en que se guarda el objeto y su

duracioacuten ( 213 ) 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 disquisicioacuten respecto a si un mismo objeto Por ejemplo una variable puede estar referenciado por dos identificadores distintos (que se refieren a la misma regioacuten de memoria) En la mayoriacutea de lenguajes de programacioacuten esta distincioacuten entre identificador y almacenamiento estaacute perfectamente establecida y suelen proporcionar mecanismos sintaacutecticos para que dos identificadores puedan referirse al mismo almacenamiento

412 Declaraciones y definiciones

sect1 Sinopsis

Utilizando un leacutexico formalista podemos decir que una declaracioacuten es una sentencia que

introduce un nombre en una unidad de compilacioacuten ( 142) daacutendole existencia semaacutentica Esto de la existencia semaacutentica es una forma elegante de decir que a partir de ahiacute el compilador sabe que cosa es (representa) ese nombre La forma de darle existencia semaacutentica a las entidades es declararlos (algo asiacute como presentarlos formalmente en el coacutedigo) Por ejemplo si declaramos una variable x o una funcioacuten func a partir de ahiacute el compilador sabe que x es una variable de tal tipo y que func es una funcioacuten de caracteriacutesticas cuales

El punto importante a resaltar aquiacute es que cada declaracioacuten asocia un nombre con un tipo de dato

lo que en C++ (una sociedad muy clasista 22) es importante ya que el conocimiento del tipo que corresponde a un identificador proporciona al compilador mucha informacioacuten sobre la entidad

representada por este (en muchas ocasiones casi toda la informacioacuten necesaria ) En especial el compilador dispone de una amplia informacioacuten acerca del uso de los tipos baacutesicos que operaciones son permitidas y que significado tienen estas operaciones

No olvidar que una declaracioacuten no hace nada maacutes que esto Es decir no antildeade ninguna otra informacioacuten distinta de relacionar una etiqueta con un tipo Posteriormente cuando esta etiqueta esteacute asociada con una entidad concreta (con una zona de memoria) las operaciones permitidas se

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

Expresiones

Asociatividad y precedencia de operadoresOrden de evaluacioacutenErrores y desbordamientosExpresiones con coma

sect49 Operadores

AritmeacuteticosAsignacioacutenManejo de BitsOperador ComaCondicionalOp de igualdadOp LoacutegicosModelado de tiposOp de PreprocesoOp de punteroRelacionalessizeoftypeidOp primariosOp antildeadidosOp UnitariosSobrecarga de OperadoresOperador Operador newOperador delete

sect410 Sentencias

Sentencias de etiqueta case defaultSentencias de seleccioacuten if hellip else else if switchSentencias de iteracioacuten while dowhile forSentencias de salto break continue goto return

sect411 Clases

CreacioacutenDeclaracioacutenNombres de ClasesAacutembito de nombresInstanciado de Clasesthis (palabra reservada)Miembros estaacuteticosClases polimoacuterficasFunciones virtualesFunciones dinaacutemicasClases abstractas

sect412 Plantillas

Funciones geneacutericasClases geneacutericas

Aunque las secciones anteriores describen completamente el lenguaje desde una perspectiva formal hemos antildeadido un capiacutetulo adicional (sect413) dedicado a los tecnicismos En eacutel se incluyen algunos consejos y reglas de buena praacutectica para la programacioacuten C++ asiacute como algunos idioms

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

41 Declaraciones

sect1 Sinopsis

Una declaracioacuten es una claacuteusula que introduce nombres en una unidad de compilacioacuten ( 142) o redeclara nombres introducidos por declaraciones previas La norma sentildeala que una declaracioacuten especifica la interpretacioacuten y atributos de estos nombres (como tipo de enlazado y de almacenamiento si es un objeto) asiacute como las condiciones para que una declaracioacuten no sea

tambieacuten una definicioacuten En la paacutegina adjunta se muestra su gramaacutetica ( Gramaacutetica)

Cada una de las introducciones unitarias que puede existir en una declaracioacuten es un declarador (declarator) Asiacute pues un declarador introduce un nombre o redeclara uno

declarado previamente La paacutegina adjunta muestra su gramaacutetica ( Gramaacutetica)

El presente capiacutetulo repasa este importante concepto y otros relacionados tales como objetos clases de almacenamiento tipos aacutembitovisibilidad duracioacuten y enlazado

El aacutembito visibilidad duracioacuten y enlazado son propiedades o caracteriacutesticas 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 definicioacuten de declaracioacuten o la exposicioacuten de su sintaxis

En el epiacutegrafe 4111 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 tambieacuten es dada a conocer mediante una declaracioacuten

411 Entidades

sect1 Presentacioacuten

En relacioacuten con los conceptos que aquiacute nos incumben consideramos que una entidad ( 121) 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 objeto-valor

Un algoritmo con informacioacuten sobre manipulacioacuten de datos Lo denominamos entidad-algoritmo o simplemente algoritmo

Respecto a los objetos-valor una posible clasificacioacuten podriacutea dividirlos en las siguientes categoriacuteas

Agregados

o matrizo estructurao unioacuteno clase unioacuten

Funciones Escalares

o Aritmeacuteticoo Enumeracioacuteno Booleanoo Punteroo Referencia

void

void ( 221) es un tipo especial con un valor muy particular ausencia de valor Los escalares son de caracteriacutesticas tales que su valor no pueden ser descompuestos en partes maacutes pequentildeas

por ejemplo un entero un valor loacutegico (cierto-falso) etc Las funciones ( 44) son principalmente algoritmo ya que estaacuten asociadas a ciertas operaciones (cierta computacioacuten) pero por convencioacuten se les puede asignar un valor es el que devuelven (puede ser void) Por su parte los agregados comparten la caracteriacutestica de que su valor puede ser descompuesto en elementos maacutes simples (escalares)

sect2 El papel de las declaraciones

Haciendo un siacutemil social podriacuteamos decir que las declaraciones son las encargadas de presentar al compilador cualquier entidad que deba existir en el programa Son por tanto el Chambelaacuten de la sociedad C++ Como en el caso de las presentaciones sociales esta presentacioacuten no se reduce a indicar el nombre tambieacuten puede sentildealarse algunas caracteriacutesticas 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

sect3 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 expresioacuten compleja que

represente uniacutevocamente al objeto ( 211 ) Cualquier intento de utilizar una declaracioacuten sin un nombre es un error aunque el nombre no tiene que responder necesariamente a un objeto o funcioacuten Ejemplo

extern int Errorchar Errorchar cptr Ok cptr nombre de punteroclass C Ok C nombre de clasetypedef unsigned int UINT Ok UINT alias para un tipo conocido

Ademaacutes del identificador las declaraciones de funciones pueden incluir ciertos atributos inline ( 4112a) virtual ( 4118a) y explicit ( 4112d1)

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 ( 21 ) Entre otros puede incluir los siguientes char wchar_t bool short int long signed unsigned float double void

Relativos al tipo de almacenamiento Determina el sitio en que se guarda el objeto y su

duracioacuten ( 213 ) 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 disquisicioacuten respecto a si un mismo objeto Por ejemplo una variable puede estar referenciado por dos identificadores distintos (que se refieren a la misma regioacuten de memoria) En la mayoriacutea de lenguajes de programacioacuten esta distincioacuten entre identificador y almacenamiento estaacute perfectamente establecida y suelen proporcionar mecanismos sintaacutecticos para que dos identificadores puedan referirse al mismo almacenamiento

412 Declaraciones y definiciones

sect1 Sinopsis

Utilizando un leacutexico formalista podemos decir que una declaracioacuten es una sentencia que

introduce un nombre en una unidad de compilacioacuten ( 142) daacutendole existencia semaacutentica Esto de la existencia semaacutentica es una forma elegante de decir que a partir de ahiacute el compilador sabe que cosa es (representa) ese nombre La forma de darle existencia semaacutentica a las entidades es declararlos (algo asiacute como presentarlos formalmente en el coacutedigo) Por ejemplo si declaramos una variable x o una funcioacuten func a partir de ahiacute el compilador sabe que x es una variable de tal tipo y que func es una funcioacuten de caracteriacutesticas cuales

El punto importante a resaltar aquiacute es que cada declaracioacuten asocia un nombre con un tipo de dato

lo que en C++ (una sociedad muy clasista 22) es importante ya que el conocimiento del tipo que corresponde a un identificador proporciona al compilador mucha informacioacuten sobre la entidad

representada por este (en muchas ocasiones casi toda la informacioacuten necesaria ) En especial el compilador dispone de una amplia informacioacuten acerca del uso de los tipos baacutesicos que operaciones son permitidas y que significado tienen estas operaciones

No olvidar que una declaracioacuten no hace nada maacutes que esto Es decir no antildeade ninguna otra informacioacuten distinta de relacionar una etiqueta con un tipo Posteriormente cuando esta etiqueta esteacute asociada con una entidad concreta (con una zona de memoria) las operaciones permitidas se

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

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

41 Declaraciones

sect1 Sinopsis

Una declaracioacuten es una claacuteusula que introduce nombres en una unidad de compilacioacuten ( 142) o redeclara nombres introducidos por declaraciones previas La norma sentildeala que una declaracioacuten especifica la interpretacioacuten y atributos de estos nombres (como tipo de enlazado y de almacenamiento si es un objeto) asiacute como las condiciones para que una declaracioacuten no sea

tambieacuten una definicioacuten En la paacutegina adjunta se muestra su gramaacutetica ( Gramaacutetica)

Cada una de las introducciones unitarias que puede existir en una declaracioacuten es un declarador (declarator) Asiacute pues un declarador introduce un nombre o redeclara uno

declarado previamente La paacutegina adjunta muestra su gramaacutetica ( Gramaacutetica)

El presente capiacutetulo repasa este importante concepto y otros relacionados tales como objetos clases de almacenamiento tipos aacutembitovisibilidad duracioacuten y enlazado

El aacutembito visibilidad duracioacuten y enlazado son propiedades o caracteriacutesticas 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 definicioacuten de declaracioacuten o la exposicioacuten de su sintaxis

En el epiacutegrafe 4111 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 tambieacuten es dada a conocer mediante una declaracioacuten

411 Entidades

sect1 Presentacioacuten

En relacioacuten con los conceptos que aquiacute nos incumben consideramos que una entidad ( 121) 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 objeto-valor

Un algoritmo con informacioacuten sobre manipulacioacuten de datos Lo denominamos entidad-algoritmo o simplemente algoritmo

Respecto a los objetos-valor una posible clasificacioacuten podriacutea dividirlos en las siguientes categoriacuteas

Agregados

o matrizo estructurao unioacuteno clase unioacuten

Funciones Escalares

o Aritmeacuteticoo Enumeracioacuteno Booleanoo Punteroo Referencia

void

void ( 221) es un tipo especial con un valor muy particular ausencia de valor Los escalares son de caracteriacutesticas tales que su valor no pueden ser descompuestos en partes maacutes pequentildeas

por ejemplo un entero un valor loacutegico (cierto-falso) etc Las funciones ( 44) son principalmente algoritmo ya que estaacuten asociadas a ciertas operaciones (cierta computacioacuten) pero por convencioacuten se les puede asignar un valor es el que devuelven (puede ser void) Por su parte los agregados comparten la caracteriacutestica de que su valor puede ser descompuesto en elementos maacutes simples (escalares)

sect2 El papel de las declaraciones

Haciendo un siacutemil social podriacuteamos decir que las declaraciones son las encargadas de presentar al compilador cualquier entidad que deba existir en el programa Son por tanto el Chambelaacuten de la sociedad C++ Como en el caso de las presentaciones sociales esta presentacioacuten no se reduce a indicar el nombre tambieacuten puede sentildealarse algunas caracteriacutesticas 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

sect3 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 expresioacuten compleja que

represente uniacutevocamente al objeto ( 211 ) Cualquier intento de utilizar una declaracioacuten sin un nombre es un error aunque el nombre no tiene que responder necesariamente a un objeto o funcioacuten Ejemplo

extern int Errorchar Errorchar cptr Ok cptr nombre de punteroclass C Ok C nombre de clasetypedef unsigned int UINT Ok UINT alias para un tipo conocido

Ademaacutes del identificador las declaraciones de funciones pueden incluir ciertos atributos inline ( 4112a) virtual ( 4118a) y explicit ( 4112d1)

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 ( 21 ) Entre otros puede incluir los siguientes char wchar_t bool short int long signed unsigned float double void

Relativos al tipo de almacenamiento Determina el sitio en que se guarda el objeto y su

duracioacuten ( 213 ) 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 disquisicioacuten respecto a si un mismo objeto Por ejemplo una variable puede estar referenciado por dos identificadores distintos (que se refieren a la misma regioacuten de memoria) En la mayoriacutea de lenguajes de programacioacuten esta distincioacuten entre identificador y almacenamiento estaacute perfectamente establecida y suelen proporcionar mecanismos sintaacutecticos para que dos identificadores puedan referirse al mismo almacenamiento

412 Declaraciones y definiciones

sect1 Sinopsis

Utilizando un leacutexico formalista podemos decir que una declaracioacuten es una sentencia que

introduce un nombre en una unidad de compilacioacuten ( 142) daacutendole existencia semaacutentica Esto de la existencia semaacutentica es una forma elegante de decir que a partir de ahiacute el compilador sabe que cosa es (representa) ese nombre La forma de darle existencia semaacutentica a las entidades es declararlos (algo asiacute como presentarlos formalmente en el coacutedigo) Por ejemplo si declaramos una variable x o una funcioacuten func a partir de ahiacute el compilador sabe que x es una variable de tal tipo y que func es una funcioacuten de caracteriacutesticas cuales

El punto importante a resaltar aquiacute es que cada declaracioacuten asocia un nombre con un tipo de dato

lo que en C++ (una sociedad muy clasista 22) es importante ya que el conocimiento del tipo que corresponde a un identificador proporciona al compilador mucha informacioacuten sobre la entidad

representada por este (en muchas ocasiones casi toda la informacioacuten necesaria ) En especial el compilador dispone de una amplia informacioacuten acerca del uso de los tipos baacutesicos que operaciones son permitidas y que significado tienen estas operaciones

No olvidar que una declaracioacuten no hace nada maacutes que esto Es decir no antildeade ninguna otra informacioacuten distinta de relacionar una etiqueta con un tipo Posteriormente cuando esta etiqueta esteacute asociada con una entidad concreta (con una zona de memoria) las operaciones permitidas se

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

o matrizo estructurao unioacuteno clase unioacuten

Funciones Escalares

o Aritmeacuteticoo Enumeracioacuteno Booleanoo Punteroo Referencia

void

void ( 221) es un tipo especial con un valor muy particular ausencia de valor Los escalares son de caracteriacutesticas tales que su valor no pueden ser descompuestos en partes maacutes pequentildeas

por ejemplo un entero un valor loacutegico (cierto-falso) etc Las funciones ( 44) son principalmente algoritmo ya que estaacuten asociadas a ciertas operaciones (cierta computacioacuten) pero por convencioacuten se les puede asignar un valor es el que devuelven (puede ser void) Por su parte los agregados comparten la caracteriacutestica de que su valor puede ser descompuesto en elementos maacutes simples (escalares)

sect2 El papel de las declaraciones

Haciendo un siacutemil social podriacuteamos decir que las declaraciones son las encargadas de presentar al compilador cualquier entidad que deba existir en el programa Son por tanto el Chambelaacuten de la sociedad C++ Como en el caso de las presentaciones sociales esta presentacioacuten no se reduce a indicar el nombre tambieacuten puede sentildealarse algunas caracteriacutesticas 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

sect3 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 expresioacuten compleja que

represente uniacutevocamente al objeto ( 211 ) Cualquier intento de utilizar una declaracioacuten sin un nombre es un error aunque el nombre no tiene que responder necesariamente a un objeto o funcioacuten Ejemplo

extern int Errorchar Errorchar cptr Ok cptr nombre de punteroclass C Ok C nombre de clasetypedef unsigned int UINT Ok UINT alias para un tipo conocido

Ademaacutes del identificador las declaraciones de funciones pueden incluir ciertos atributos inline ( 4112a) virtual ( 4118a) y explicit ( 4112d1)

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 ( 21 ) Entre otros puede incluir los siguientes char wchar_t bool short int long signed unsigned float double void

Relativos al tipo de almacenamiento Determina el sitio en que se guarda el objeto y su

duracioacuten ( 213 ) 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 disquisicioacuten respecto a si un mismo objeto Por ejemplo una variable puede estar referenciado por dos identificadores distintos (que se refieren a la misma regioacuten de memoria) En la mayoriacutea de lenguajes de programacioacuten esta distincioacuten entre identificador y almacenamiento estaacute perfectamente establecida y suelen proporcionar mecanismos sintaacutecticos para que dos identificadores puedan referirse al mismo almacenamiento

412 Declaraciones y definiciones

sect1 Sinopsis

Utilizando un leacutexico formalista podemos decir que una declaracioacuten es una sentencia que

introduce un nombre en una unidad de compilacioacuten ( 142) daacutendole existencia semaacutentica Esto de la existencia semaacutentica es una forma elegante de decir que a partir de ahiacute el compilador sabe que cosa es (representa) ese nombre La forma de darle existencia semaacutentica a las entidades es declararlos (algo asiacute como presentarlos formalmente en el coacutedigo) Por ejemplo si declaramos una variable x o una funcioacuten func a partir de ahiacute el compilador sabe que x es una variable de tal tipo y que func es una funcioacuten de caracteriacutesticas cuales

El punto importante a resaltar aquiacute es que cada declaracioacuten asocia un nombre con un tipo de dato

lo que en C++ (una sociedad muy clasista 22) es importante ya que el conocimiento del tipo que corresponde a un identificador proporciona al compilador mucha informacioacuten sobre la entidad

representada por este (en muchas ocasiones casi toda la informacioacuten necesaria ) En especial el compilador dispone de una amplia informacioacuten acerca del uso de los tipos baacutesicos que operaciones son permitidas y que significado tienen estas operaciones

No olvidar que una declaracioacuten no hace nada maacutes que esto Es decir no antildeade ninguna otra informacioacuten distinta de relacionar una etiqueta con un tipo Posteriormente cuando esta etiqueta esteacute asociada con una entidad concreta (con una zona de memoria) las operaciones permitidas se

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

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 ( 21 ) Entre otros puede incluir los siguientes char wchar_t bool short int long signed unsigned float double void

Relativos al tipo de almacenamiento Determina el sitio en que se guarda el objeto y su

duracioacuten ( 213 ) 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 disquisicioacuten respecto a si un mismo objeto Por ejemplo una variable puede estar referenciado por dos identificadores distintos (que se refieren a la misma regioacuten de memoria) En la mayoriacutea de lenguajes de programacioacuten esta distincioacuten entre identificador y almacenamiento estaacute perfectamente establecida y suelen proporcionar mecanismos sintaacutecticos para que dos identificadores puedan referirse al mismo almacenamiento

412 Declaraciones y definiciones

sect1 Sinopsis

Utilizando un leacutexico formalista podemos decir que una declaracioacuten es una sentencia que

introduce un nombre en una unidad de compilacioacuten ( 142) daacutendole existencia semaacutentica Esto de la existencia semaacutentica es una forma elegante de decir que a partir de ahiacute el compilador sabe que cosa es (representa) ese nombre La forma de darle existencia semaacutentica a las entidades es declararlos (algo asiacute como presentarlos formalmente en el coacutedigo) Por ejemplo si declaramos una variable x o una funcioacuten func a partir de ahiacute el compilador sabe que x es una variable de tal tipo y que func es una funcioacuten de caracteriacutesticas cuales

El punto importante a resaltar aquiacute es que cada declaracioacuten asocia un nombre con un tipo de dato

lo que en C++ (una sociedad muy clasista 22) es importante ya que el conocimiento del tipo que corresponde a un identificador proporciona al compilador mucha informacioacuten sobre la entidad

representada por este (en muchas ocasiones casi toda la informacioacuten necesaria ) En especial el compilador dispone de una amplia informacioacuten acerca del uso de los tipos baacutesicos que operaciones son permitidas y que significado tienen estas operaciones

No olvidar que una declaracioacuten no hace nada maacutes que esto Es decir no antildeade ninguna otra informacioacuten distinta de relacionar una etiqueta con un tipo Posteriormente cuando esta etiqueta esteacute asociada con una entidad concreta (con una zona de memoria) las operaciones permitidas se

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

realizaraacuten sobre esta entidad Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcioacuten)

sect11 La declaracioacuten se completa con la definicioacuten En esta fase se concreta la creacioacuten de la entidad (donde y cuando) Si es un objeto-dato se le asigna memoria fiacutesica y posiblemente se inicializa Ejemplo int x = 3 Si es un algoritmo (funcioacuten) se establece su coacutedigo En muchos casos la declaracioacuten y definicioacuten se realiza en la misma sentencia En otros casos la declaracioacuten mantiene su sentido original de ser una simple exposicioacuten de un tipo de entidad con un

nombre y posiblemente alguacuten atributo adicional ( 411) en este caso la declaracioacuten se denomina tambieacuten referencia

Como puede verse las declaraciones pueden definir yo referenciar Cualquier declaracioacuten que ademaacutes reserve almacenamiento a un objeto o funcioacuten es una definicioacuten Asiacute pues el concepto definicioacuten implica una iniciacioacuten del objeto (en el sentido de que empieza a tener existencia fiacutesica al asignaacutersele espacio en memoria) En lo sucesivo para evitar ambiguumledades utilizaremos declaracioacuten en el sentido referenciar y definicioacutencuando se trata de asignar memoria fiacutesica y posiblemente inicializar esta con valores determinados

En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semaacutenticas en especial cuando los objetos son instancias de clases

sect12 Declaracioacuten Simplemente asocia un identificador con un tipo (existencia semaacutentica) La

declaracioacuten de una funcioacuten se denomina prototipo ( 441) La gramaacutetica C++ exige que la declaracioacuten de una entidad se indique primero su tipo y despueacutes el identificador con el que se la conoceraacute en adelante

Ejemplos

extern int xclass Cint func(int x char c) prototipo

Observe que la gramaacutetica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores

int x y zC c1 c2 c3

Pero hay que prestar atencioacuten a este tipo de sentencias porque pueden deparar sorpresas

int x y z Ok x y z son tipo intC c1 c2 c3 Atencioacuten c1 es tipo C mientras que c2 y c3 son tipo C

Despueacutes de la declaracioacuten 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 informacioacuten Ejemplo

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

struct E1 declara que E1 es tipo structstruct E2 pe2 declara que pe2 es tipo E2 (puntero-a-struct-E2)E1 ep1 declara que pe1 es tipo E1 (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estaacuten acompantildeadas por una definicioacuten adecuada) Las entidades en esta situacioacuten (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 tamantildeo indefinido Ejemplo

class C clase declarada pero no definidachar m1[ ] matriz de tamantildeo indefinidoC matriz[5] matriz de tipos incompletos

Nota para justificar que tiene unas caracteriacutesticas de tipo que podriacuteamos denominar

restringidas el Estaacutendar C++ (sect39) establece que el tipo void ( 221) es tambieacuten un tipo incompleto (que no podraacute nunca llegar a ser completo)

Salvo en las contadas ocasiones en que no se requiere conocer el tamantildeo del objeto los tipos incompletos no pueden ser utilizados en la definicioacuten de otros tipos aunque siacute en su declaracioacuten -tambieacuten incompleta- Ejemplo

extern C cptr puntero a tipo incompletotypedef int UNDA[] matriz incompletaUNDA aptr puntero a tipo incompletoclass D UNDA apptr Error puntero a tipo incompleto en definicioacuten

En los casos en que no es necesario conocer el tamantildeo del objeto incompletamente declarado siacute es posible utilizarlos en la definicioacuten de otras entidades Esto ocurre tiacutepicamente cuando la definicioacuten solo contiene punteros y referencias al objeto incompleto ya que en ambos casos el tamantildeo siempre es el mismo Por ejemplo seriacutea vaacutelido el siguiente trozo de coacutedigo

class A Clase declarada pero no definida aquiacute la suponemos definida en otra unidad de compilacioacuten class B public A aptr void foo (const Aamp a)

sect13 Iniciacioacuten asigna memoria fiacutesica al objeto (existencia fiacutesica) Si no se produce una inmediata asignacioacuten de valores determinados la zona asignada puede contener basura Ejemplo

int ptrint x

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

sect14 Definicioacuten asocia un identificador con un tipo y le asigna espacio en memoria (declaracioacuten + iniciacioacuten) Observe que despueacutes de la definicioacuten el objeto no tiene porqueacute estar inicializado Es decir si es un objeto-dato el espacio asignado puede contener basura

En el caso de funciones la definicioacuten se realiza cuando se establece el cuerpo de la funcioacuten En el caso de clases cuando se describen cuales seraacuten sus propiedades y meacutetodos Ejemplo

int xint func(int x char c) return (x + c) class C int x char c

Adelantemos aquiacute que en C++ existe la denominada regla de una sola definicioacuten ODR (One Definition Rule) seguacuten la cual cualquier nombre puede ser declarado varias veces en cada unidad de compilacioacuten (con la condicioacuten de que estas declaraciones sean ideacutenticas) pero solo puede

definirse una vez Al tratar de los constructores y destructores ( 4112d) veremos que en C++ es muy importante la correcta creacioacuten e inicializacioacuten de los objetos por lo que en el caso de los

tipos complejos ( 22) la creacioacuten e inicializacioacuten estaacuten indisolublemente unidas y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente

sect15 Inicializacioacuten asignar valores concretos al objeto (existencia utilizable) a partir de aquiacute el espacio de memoria contiene datos correctos Ejemplo

x = 5 inicia x con el valor 5int ptr = ampx inicia ptr con la direccioacuten de xint y = y inicia y con su propio valor indefinidoC c Valores por defecto asignados por el constructorC d = 15 z Valores asignados de forma expliacutecita

sect16 Destruccioacuten 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 seraacuten basura para el proacuteximo objeto que ocupe dicho espacio de memoria Ejemplo

delete c

sect17 De acuerdo con lo anterior puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases

Declarar Relacionar un identificador (nombre) con un tipo

Iniciar Reservar almacenamiento

Inicializar Asignarle valores

Destruir Desasignacioacuten semaacutentica y fiacutesica

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

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

sect2 Al llegar a este punto hay que hacer una matizacioacuten importante Cuando en un programa C++ se encuentra una expresioacuten del tipo int nteacutecnicamente hablando se trata solo de una declaracioacuten Sin embargo el compilador ya tiene toda la informacioacuten necesaria (en este caso) y le asigna un espacio de memoria (momentaacuteneamente puede estar lleno de basura) Por esta razoacuten a veces se dice que una expresioacuten como la anterior es una definicioacuten En estos casos la uacutenica forma de asegurarse que el compilador interpreta la sentencia en sus teacuterminos exactos (solo declaracioacuten) es antildeadiendo el especificador extern Ejemplo

extern int n

Esto garantiza que el compilador sepa que es solo una declaracioacuten y que la definicioacuten (y el almacenamiento) estaacute en alguacuten otro sitio Noacutetese que lo anterior (conocer toda la informacioacuten con solo la declaracioacuten) solo ocurre con las declaraciones de variables no asiacute con las funciones En una declaracioacuten de funcioacuten (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 verificacioacuten estaacutetica de tipos) ya que falta

el cuerpo (definicioacuten) de la funcioacuten De hecho en la declaracioacuten de cualquier funcioacuten puede

suponerse que estaacute impliacutecito el especificador extern ( 418d)

Maacutes detalles y ejemplos ( Declaraciones y definiciones)

sect3 Regla de una sola definicioacuten

Esta regla conocida tambieacuten por su acroacutenimo ingleacutes ODR establece que en cada programa especialmente si es multifichero puede haber muchas referencias al mismo identificador pero solo

se permite una definicioacuten para cada identificador en cada espacio de nombres ( 4111) Las entidades que se pueden declarar incluyen

Variables Funciones expliacutecitas y geneacutericas Clases expliacutecitas y geneacutericas y sus miembros Tipos Etiqueta estructura unioacuten y enumeracioacuten Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracioacuten 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 definicioacuten de cualquiera de las entidades antes enunciadas

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

Dentro de un mismo fichero pueden existir muacuteltiples typedef ( 321a) o macro definiciones

(define 4910b) siempre que la definicioacuten resultante sea la misma lo que es conocido como redefinicioacuten benigna (benign redefinition)

De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del coacutedigo fuente en que es declarado [1] Las excepciones a esta regla conocidas

como referencias adelantadas ( 4114a) son llamadas a funciones etiquetas de clases estructuras o uniones no declaradas

A pesar de lo anterior el lector habraacute observado que es frecuente la praacutectica de incluir definiciones en ficheros de cabecera digamos pe ltcabecerahgt y que maacutes tarde pueden aparecer sentencias del tipo include ltcabecerahgt en varios fuentes del mismo programa lo que conduciriacutea a pensar que se contraviene la regla [6]

La razoacuten de que en estos casos no se produzcan errores es que esta regla no debe tomarse al pieacute de la letra En realidad el compilador acepta la aparicioacuten en el coacutedigo de maacutes de una definicioacuten de una entidad y las toma como imaacutegenes de una sola definicioacuten siempre que se cumplan las siguientes condiciones

Las definiciones aparezcan en distintas unidades de compilacioacuten

Resulten ideacutenticas token a token para el parser ( 14) El significado de los tokens sea ideacutentico en todas estas unidades de compilacioacuten (no

ocurra por ejemplo que un siacutembolo tenga un significado en un moacutedulo y otro distinto en el siguiente debido a un typedef)

sect4 Declaraciones

En la praacutectica una declaracioacuten 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 estaacuten separados por comas y toda la lista terminada en punto y coma Una declaracioacuten de variables puede tener el siguiente aspecto

tipo-de-dato var1 lt=inic1gt var2 lt=inic2gt

donde var1 var2 es cualquier secuencia de identificadores distintos con iniciadores lt=inicXgt opcionales Cada una de las variables es declarada del tipo sentildealado por tipo-de-dato Por ejemplo

int x = 1 y = 2 z

Esta declaracioacuten [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)

Declaracioacuten tipo impliacutecito de nomb Ejemplo de usotipoX nomb tipoX int conttipoX nomb[] matriz (abierta)de tipoX int cont[]tipoX nomb[3] matriz de tres elementos tipoX int cont[3]

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

nomb[0] nomb[1] y nomb[2])tipoX nomb Puntero-a-tipoX int conttipoX nomb[] Matriz de punteros-a-tipoX int cont[]tipoX (nomb[]) equivalente al anterior int (cont[])tipoX (nomb)[] -Puntero a matriz de tipoX int (cont) []tipoX ampnomb Referencia a tipoX int ampconttipoX nomb() Funcioacuten devolviendo tipoX int cont()tipoX nomb() Funcioacuten devolviendo puntero-a-tipoX int cont()tipoX (nomb()) equivalente al anterior int (cont())tipoX (nomb)() -Puntero a funcioacuten devolviendo tipoX int (cont)()

Nota observe la necesidad de pareacutentesis en (nomb)[] y (nomb)() Es asiacute porque en

ambos la precedencia ( E490a) del declarador de matrices [ ] y del declarador de funciones ( ) es mayor que el declarador de puntero En cambio el pareacutentesis en (nomb[]) es opcional

sect5 Definiciones

Se tiene una definicioacuten cuando el compilador tiene informacioacuten suficiente para construir en memoria una imagen de la entidad Podemos suponer que la definicioacuten es una reserva o asignacioacuten de espacio en un sitio concreto de memoria

int xchar chlong zint dias[7]struct S int a int b char ptrfloat power2(float n) return nn

La definicioacuten 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 declaracioacuten 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 definicioacuten propiamente dicha se realiza en una segunda fase denominada de implementacioacuten en la que se precisan todos los detalles incluyendo las definiciones de todas

las funciones-miembro posible lista de iniciadores ( 4112d3) Etc

El subconjunto de la declaracioacuten que contiene solo referencias a las propiedades y meacutetodos puacuteblicos se conoce como interfaz de la clase Se supone que la interfaz contiene toda la informacioacuten 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

sect6 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 creacioacuten concluye con la definicioacuten)

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

Cuando se inicia un objeto debe estar ya declarado y definido (aunque todos los pasos puedan estar impliacutecitos 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 esteacute previamente ocupado por valores sin sentido (basura)

En general la inicializacioacuten se realiza mediante asignaciones que pueden realizarse en el momento de la declaracioacuten o despueacutes pero existen posibilidades sintaacutecticas especiales para

algunos tipos Por ejemplo las matrices ( 431) estructuras ( 452) uniones ( 46) y las instancias de clases (objetos) En particular estas uacuteltimas disponen de funciones especiales

encargadas de estos menesteres los constructores ( 4112d3) En los siguientes epiacutegrafes se exponen algunas reglas y consideraciones sobre el asunto

sect7 Reglas de inicio

sect71 El Estaacutendar establece que dentro de cada unidad de compilacioacuten la inicializacioacuten de los objetos se realizaraacute en el mismo orden de su definicioacuten [7]

sect72 Si un identificador tiene aacutembito de bloque y especificacioacuten de enlazado externo o interno la declaracioacuten no puede contener ninguna inicializacioacuten (debe ser una mera referencia) Ejemplo

extern long peso = 1000 L1 Error extern long peso L2 correcto

Nota una sentencia como L1 puede no producir error porque el compilador sencillamente ignora la claacuteusula extern Recuerde que una declaracioacuten con inicializador es siempre una definicioacuten

sect73 Recuerde que fuera de los bloques de funciones o clases en eacutel aacutembito global de fichero no puede existir ninguacuten tipo de sentencia distinta de definiciones o declaraciones Por ejemplo considere el siguiente programa

include ltiostreamhgtint a L2 Ok declaracioacutena = 13 Error Asignacioacuten no permitida aquiacuteint b = 23 Ok definicioacutenint c = b Ok definicioacutencout ltlt c = ltlt c ltlt endl Error sentencia no permitida aquiacute

int main() ===================================== cout ltlt a = ltlt a ltlt endl Ok sentencia permitida a = 13 Ok Asignacioacuten permtida aquiacute cout ltlt a = ltlt a ltlt endl int d M4 Ok declaracioacuten cout ltlt d = ltlt d ltlt (Basura) ltlt endl d = 33 Ok Inicializacioacuten

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

cout ltlt d = ltlt d ltlt endl

Salida despueacutes de eliminadas las sentencias erroacuteneas

a = 0a = 13d = 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 L2 del ejemplo anterior equivale a

int a = 0

lo que explica la primera salida En cambio esto no ocurre con las variables locales ( 418a) o

creadas en la zona de almacenamiento persistente ( 132) asiacute que la variable d declarada en M4 no es inicializada por defecto y contiene basura

sect74 Las variables escalares pueden inicializarse en el mismo punto de su declaracioacuten siguiendo el nombre de la variable con el signo igual y una expresioacuten (en otras palabras mediante una asignacioacuten utilizando una expresioacuten como Rvalue) Ejemplo

int x = 1char simplecomilla = long msdia = 1000L 60L 60L 24L milisegundos del diacutea

Si un objeto tiene duracioacuten automaacutetica y no es inicializado su contenido es indeterminado (puede ser simplemente basura) En estas y en las variables de registro el iniciador no estaacute restringido a una constante Puede ser cualquier expresioacuten 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

sect76 Para variables externas y estaacuteticas la inicializacioacuten ocurre conceptualmente una sola vez antes que el programa comience su ejecucioacuten

Si no son inicializadas expliacutecitamente la inicializacioacuten ocurre antes que cualquier otra en el programa adoptaacutendose por defecto los valores que siguientes

o Cero si es de tipo aritmeacuteticoo Nulo si es un puntero

Si son inicializadas mediante expresiones constantes esta inicializacioacuten ocurre antes que

la de los objetos automaacuteticos Los inicializadores de objetos estaacuteticos pueden ser

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

cualquier expresioacuten que incluya constantes y variables o funciones que hayan sido declaradas previamente

sect77 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 ideacutenticos

int x = 97char ch = achar m1[] = Holachar m2[4] = Hola0char m3[4] = Holch0char m4[4] = Holf(97)0char m5[4] = Holf(x)0char 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 antildeada informacioacuten a la contenida en la declaracioacuten previa Ejemplo

extern int a[] L1 no se especifica tamantildeo (matriz abierta)struct mystruct L2 no especifica miembros (decl anticipada)int a[3] = 1 2 3 se especifica tamantildeo y se iniciastruct mystruct int i j se antildeade declaracioacuten de miembros

Obseacutervese que la expresioacuten de L1 es una declaracioacuten de a como variable externa la liacutenea L2 es en cambio una declaracioacuten anticipada en el sentido indicado en 451e Lo uacutenico que hace esta sentencia es declarar mystruct como de aacutembito global al fichero Se trata pues de matices distintos en ambas declaraciones

sect78 Inicio de matrices estructuras y uniones

Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracioacuten) 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 inicializacioacuten de matrices de caracteres normales y anchos (

323)

sect781 Puede iniciarse una matriz de caracteres con una cadena literal opcionalmente entre

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

corchetes Cada caraacutecter de la cadena incluyendo el terminador nulo (incluido automaacuteticamente) 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[] = Jorge0

sect782 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 coacutedigos de la cadena alfanumeacuterica ancha inician elementos sucesivos de la matriz

sect783 La inicializacioacuten de estructuras y uniones se detalla en los apartados correspondientes (

452)

sect8 Definicioacuten provisional

En contra de lo que ocurre en C en C++ no existe el concepto de declaracioacuten provisional [3] Una declaracioacuten de dato externo sin un especificador de tipo de almacenamiento es tomado siempre como una definicioacuten por lo que cualquier inicializacioacuten posterior daraacute lugar a un error de Declaracioacuten muacuteltiple Por ejemplo

int x declara xint x Error Muacuteltiple declaracioacuten de xint y declara yint y = 4 Error Multiple declaracioacuten de yint z = 5 Legal z declarado e iniciado a 5int z = 6 Error Muacuteltiple declaracioacuten de z

413 Aacutembito

sect1 Sinopsis

Aunque los iremos tratando con maacutes detalle permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones aacutembito visibilidad y vida

Cada identificador es introducido en el coacutedigo mediante una declaracioacuten A partir de este punto de

declaracioacuten es conocido por el compilador en una regioacuten que llamaremos aacutembito es la zona

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

en que la declaracioacuten tiene efecto Dentro de este aacutembito no puede existir otra declaracioacuten con el mismo identificador [3]

Nota el aacutembito corresponde con una zona del fuente englobada entre llaves una lista de paraacutemetros en una funcioacuten o plantilla o el espacio de una unidad de compilacioacuten no incluido en cualquier otro aacutembito

Dentro del aacutembito 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 praacutectica ocurre que cada identificador solo es visible en algunas regiones de su aacutembito (que pueden ser discontinuas) El conjunto de estas regiones es su aacuterea de visibilidad (scope)

La razoacuten por la que un identificador deja de ser visible dentro de su aacutembito es que sea eclipsado por otra declaracioacuten expliacutecita que utiliza el mismo nombre La nueva declaracioacuten puede ocurrir en un bloque de coacutedigo anidado (en el mismo no es posible la nueva declaracioacuten) o en una clase derivada

Nota para determinar el scope de un identificador es usual referirse al aacutembito potencial de su declaracioacuten En principio su scope es el de su potencial a menos que este contenga otra declaracioacuten del mismo nombre en cuyo caso el aacutembito potencial de la nueva declaracioacuten 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 aacutembito scope y visibilidad son atributos de un identificador en el coacutedigo [2] Observe que las dos primeras se refieren a una zona del coacutedigo (un conjunto de sentencias) mientras que la visibilidad es una propiedad puntual el estado visibleinvisible del objeto puede cambiar en cada liacutenea dentro del aacutembito El conjunto de todas en las que estaacute visible constituye su aacuterea de visibilidad o scope

Ejemplo

int x declaracioacuten de x punto de declaracioacuten de xvoid main () x = 10 Ok x estaacute en scope (1 variable x) int x = 11 nueva declaracioacuten de x (2 variables x) intamp x1 = x referencia a la x anterior cout ltlt x -gt 11 cout ltlt x -gt 10 observe el nombre cualificado x = 12 nueva declaracioacuten de x (3 variables x) cout ltlt x -gt 12 cout ltlt x -gt 10 cout ltlt x1 -gt 11 (uacutenico acceso a este x) cout ltlt x -gt 11 (2 variables x) (0 variables)

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

La vida (Lifetime) es un atributo de tiempo de ejecucioacuten (runtime) Es el tiempo en que una

entidad se mantiene en memoria Es decir desde que es creado hasta que es destruido ( 415)

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 momentaacuteneamente) y una

zona de memoria donde estaacute la entidad que referencia la etiqueta (el Rvalue 215) que el identificador tiene su propio aacutembito y visibilidad y que la uacutenica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo sentildeale -un puntero-) En estas circunstancias al menos teoacutericamente pueden suponerse diversas situaciones

sect11 El identificador estaacute en aacutembito (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 = 1x = j +10cout ltlt x = ltlt x ltlt endl

sect12 El identificador estaacute en aacutembito (existe y estaacute vivo) pero fuera de scope el almacenamiento sigue intacto Para todos los efectos es como si los datos no existieran puede que maacutes tarde vuelva a estar en aacutembito (vuelva a ser visible) Es la tiacutepica situacioacuten en que un identificador es ocultado (eclipsado o tapado) momentaacuteneamente por otro del mismo nombre en un bloque maacutes profundo Por ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta x anterior mientras dure el bucle cout ltlt x ltlt endl la x original vuelve a ser visible

sect13 El identificador estaacute en aacutembito vivo y visible pero su zona de memoria estaacute 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 situacioacuten anoacutemala pero puede presentarse por muacuteltiples causas Por ejemplo un objeto ha sido eliminado de memoria mientras que existen referencias vaacutelidas al mismo (punteros) Tambieacuten porque no hemos inicializado adecuadamente la variable o porque alguacuten puntero descontrolado ha metido datos en el sitio inadecuado Los resultados son impredecibles Por ejemplo al realizar una operacioacuten con ese objeto recibimos un error de runtime

sect14 El identificador estaacute fuera de aacutembito (muerto y por supuesto invisible) el compilador no puede hacer maacutes uso de eacutel 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 olvidaacutendose el destructor de una clase o usar el operador delete antes de salir de una funcioacuten El resultado es que la memoria sigue conservando los datos inuacutetilmente Es la tiacutepica situacioacuten de peacuterdida de memoria por el

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

programa Es un error de programacioacuten tiacutepico en sistemas que no disponen de un recolector automaacutetico de basura como es el caso de C++ Tambieacuten la causa de que aparezcan lenguajes como Java que siacute disponen de esta caracteriacutestica

sect2 Clases de aacutembito

En C++ hay siete categoriacuteas de aacutembitos De sentencia de bloque (o local) de funcioacuten de prototipo de funcioacuten de fichero de clase y deespacio de nombres El aacutembito depende de como y donde es declarado el identificador

Aparte del aacutembito de Clase (que no existe en C) las reglas de aacutembito para C++ son las mismas que en C con la salvedad que a diferencia de este C++ permite que la declaracioacuten de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia Esta especial flexibilidad implica que deba prestarse especial atencioacuten cuando se interpreten cuestiones tales como punto de declaracioacuten y ldquoenclosing scoperdquo Por ejemplo las siguientes declaraciones son correctas en C++ pero no en C

void main(void) int i = 100 cout ltlt Es el numero ltlt i ltlt endl char ch = A cout ltlt Es la letra ltlt ch ltlt endl

Para ser compilado como C tendriacutean que haberse declarado las variables antes que ninguna ejecucioacuten de funcioacuten Por ejemplo

void main(void) int i = 100 char ch = A cout ltlt Es el numero ltlt i ltlt endl cout ltlt Es la letra ltlt ch ltlt endl

sect21 Aacutembito de Sentencia

C++ soporta declaraciones en expresiones condicionales pueden declararse variables dentro de las expresiones de las sentencias for if while yswitch entonces el aacutembito de las variables es el de la sentencia En el caso de if el aacutembito incluye tambieacuten el bloque else Ejemplo

for (j = 0 jgt10 j++) comienza el aacutembito de j int x = 0 comienza el aacutembito de x termina el aacutembito de j x (ver nota)

Nota C++Builder incluye la opcioacuten de la opcioacuten -Vd de compilacioacuten que permite modificar el

aacutembito de las variables declaradas dentro de las sentencias for ( 4103)

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

sect22 Aacutembito de Bloque

El aacutembito de un identificador con aacutembito local (o de bloque) empieza en el punto de declaracioacuten y termina al final del bloque que contiene la declaracioacuten (el denominado bloque contenedor) Ejemplo

char c = c comienza el aacutembito de c int x = 0 comienza el aacutembito de x termina el aacutembito de c x

El aacutembito de los paraacutemetros declarados en la definicioacuten de una funcioacuten es el del bloque que define dicha funcioacuten Ejemplo

int func (int x int y) comienza el aacutembito de x y int y = 12 Error declaracioacuten duplicada return (x + y) termina el aacutembito de x y

sect23 Aacutembito de Funcioacuten

Los uacutenicos identificadores que tienen aacutembito de funcioacuten son las etiquetas de goto ( 4101) razoacuten por la cual sus nombres deben ser uacutenicos en la funcioacuten Su aacutembito es el de la funcioacuten que las contiene de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcioacuten en que se han declarado

Los identificadores de funcioacuten tienen enlazado externo ( 144) lo que significa que pertenecen al aacutembito 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 (recursioacuten) pero el bloque de coacutedigo que engloba el cuerpo de cada funcioacuten incluyendo sus variables es un espacio oculto no puede ser accedido directamente desde su exterior Por esta razoacuten no es posible por ejemplo realizar un salto goto a una etiqueta en otra funcioacuten La uacutenica manera de acceder a una funcioacuten es mediante una llamada a la misma siguiendo el formato especiacutefico definido en su prototipo El uacutenico valor que se puede manejar directamente es el que devuelve y

auacuten asiacute no es el valor original sino una copia modelada de este (ver la sentencia return 447)

Los nombres contenidos en la lista de paraacutemetros formales de una funcioacuten pertenecen al aacutembito del bloque maacutes externo de la funcioacuten (el que define el cuerpo de la funcioacuten)

Una consecuencia de que todas las funciones comparten el mismo aacutembito global es que no puedan declararse funciones dentro de funciones

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

Nota las cosas eran como se han descrito hasta la introduccioacuten en el lenguaje del mecanismo

de espacio de nombres ( 4111) momento desde el cual C++ permite la existencia de funciones fuera del espacio global [1] Ademaacutes las clases funcionan como auteacutenticos

subespacios de nombres ( 4111c1) por lo que tambieacuten pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global

sect24 Aacutembito de Prototipo

Los nombres declarados en la lista de paraacutemetros de un prototipo de funcioacuten (que no sea parte de una declaracioacuten) tienen aacutembito 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

sect25 Aacutembito de Fichero

Los identificadores con aacutembito de fichero son llamados tambieacuten globales o externos Son declarados fuera de cualquier bloque clase o funcioacuten Su aacutembito abarca desde el punto de declaracioacuten hasta el final del fichero (por esta razoacuten se suelen declarar al principio del fichero justo despueacutes de las directivas de preproceso)

sect26 Aacutembito de Clase

Una clase ( 411) es una coleccioacuten de elementos (miembros) junto con las operaciones que se realizan con ellos El teacutermino aacutembito 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 aacutembito muy especiales

El nombre N de un miembro de una clase C tiene aacutembito ldquolocal a Crdquo y puede ser utilizado solo en las siguientes situaciones

En funciones miembro (meacutetodos) de C En expresiones tales como cN donde c es un objeto de C (Selector directo de

miembro 4916) En expresiones tales como cptr-gtN donde cptr es un puntero a una instancia

de C (Selector indirecto de miembro 4916)

En expresiones tales como CN o DN 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 4112a) de C no son miembros de C sus nombres simplemente tienen aacutembito de la clase C

sect27 Aacutembito de espacio de nombres

El espacio de nombre es el aacutembito en el que un identificador debe ser uacutenico A este respecto C usa cuatro clases distintas de identificadores

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

Nombres de etiquetas goto Deben ser uacutenicas dentro de la funcioacuten en que se han declarado (el goto tiene aacutembito de funcioacuten)

Nombres estructuras uniones y enumeraciones Deben ser uacutenicas dentro del bloque en que se han definido Las etiquetas definidas fuera de cualquier funcioacuten deben ser uacutenicas (ya que son globales al fichero)

Nombres de miembros de estructuras y uniones Deben ser uacutenicos dentro de la estructura o unioacuten en que se han definido No existe restriccioacuten en el tipo de miembros del mismo nombre en diferentes estructuras

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

C++ tiene una palabra clave namespace ( 4111) 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 raiacutez tienen aacutembito de todo el programa (de la aplicacioacuten) siempre que se hayan definido como extern en el resto de los moacutedulos A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacioacuten cuyos nombres predefinidos que son incluidas automaacuteticamente en cualquier programa C++ para usos varios como fechas horas etc (

413a)

sect3 Ocultacioacuten

Un nombre puede ser ocultado por una declaracioacuten expliacutecita del mimo nombre en un bloque maacutes profundo o en una clase Ejemplo

int x = 3 jfor (j = 0 jgt10 j++) int x = 0 oculta al anterior cout ltlt x ltlt endl la x original vuelve a ser visible

Los paraacutemetros formales de las funciones ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x y espacio globalfunc(double x double y) x e y globales no son visibles aquiacute

sect31 Acceso cualificado

El miembro oculto m de una clase CL es todaviacutea accesible utilizando el operador de acceso a

aacutembito ( 4919) con un nombre de claseCLm

Un nombre de aacutembito global (de fichero) oculto puede ser todaviacutea referenciado utilizando el operador Ejemplo

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

include ltiostreamgtusing namespace std

int x = 1 x-globalint main() ============== cout ltlt 1 x = ltlt x ltlt endl x = 2 se refiere a x-global cout ltlt 2 x = ltlt x ltlt endl int x = 4 Nueva x (x-de-main) oculta a la anterior for (int j = 0 jlt1 j++) int x = 3 Nueva x (x-de-for) oculta a la anterior cout ltlt 3 x = ltlt x ltlt endl x = 5 se refiere a x-global cout ltlt 4 x = ltlt x ltlt endl cout ltlt 5 x = ltlt x ltlt endl

Salida

1 x = 12 x = 23 x = 34 x = 45 x = 5

sect31a Un nombre de clase puede ser ocultado por el nombre de un objeto funcioacuten o enumerador declarado dentro de su aacutembito con independencia del orden en que se hubiesen declarado los nombres Aunque la clase oculta puede ser todaviacutea accesible precediendo su identificador con la palabra clave apropiada class estruct o union

Ejemplo

class C

int main() ============= int C C c Error clase C no definida (oculta por int C) class C c Ok compila sin dificultad

sect4 Punto de declaracioacuten

A todos estos efectos el punto de declaracioacuten de un nombre x es inmediatamente despueacutes de su declaracioacuten completa pero antes de su inicializador si es que existe alguno

sect5 Acceso a entidades

Cuando el compilador encuentra en el coacutedigo la utilizacioacuten de un identificador intenta relacionarlo con alguna declaracioacuten previa de dicho nombre Este proceso es conocido como buacutesqueda de

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

nombre (Name-lookup) El proceso puede asociar maacutes de una declaracioacuten con un nombre si este corresponde a una funcioacuten (funciones sobrecargadas) en este caso la seleccioacuten de la definicioacuten adecuada sigue al name-lookup en un proceso conocido como resolucioacuten de

sobrecarga Ver en la hoja adjunta una somera descripcioacuten del proceso ( Name-lookup)

413a Tipos y variables globales

sect1 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 caacutelculos de fechas horas etc

sect2 Variables y tipos globales maacutes frecuentes

En concreto Borland C++ utiliza las siguientes [1]

Etiqueta Descripcioacuten

_8087 Sintaxis extern int _8087

Esta variable adopta un valor distinto de cero si la loacutegica de

autodeteccioacuten del moacutedulo inicial ( 15) 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

funcioacuten main ( 444)

_argv Sintaxis extern char _argv extern wchar_t _wargv

Esta variable adopta el valor pasado al argumento argv de la

funcioacuten main (ver el punto anterior ) _wargv es la versioacuten Unicode

_ctype Sintaxis extern char _ctype[]

Esta variable es una matriz que incluye informacioacuten sobre atributos de los caracteres Cada elemento de la matriz es un conjunto de bits describiendo determinadas caracteriacutesticas del caraacutecter La matriz es utilizada por determinadas funciones de la Libreriacutea Estaacutendar

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

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 ( 171) adopta un valor distinto de cero si el valor DST estaacute 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 ltlt _dylight -gt 1

Comentario El sistema estaacute en horario de verano con una hora de adelanto sobre la que corresponderiacutea por su uso horario

_doserrno

_environ

errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Libreriacutea 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 coacutedigo de error del Sistema que es por contra almacenado en doserror Finalmente en otras ocasiones el coacutedigo es reflejado en errno y no en doserrno

Ejemplo para mostrar los errores del sistema

int i = 0while(_sys_errlist[i++]) printf(sn _sys_errlist[i])return 0

_floatconvert

_fmode Esta variable controla si la apertura de ficheros se realizaraacute por defecto en modo binario o texto para las funciones de Libreriacutea

Estaacutendar fopen() fdopen() y freopen() ( 552) 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 funcioacuten de libreriacutea 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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

_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 horafecha y calculada por la funcioacuten de Libreriacutea tzset() En Win32 este valor es obtenido del Sistema Operativo Ejemplo

cout ltlt _timezone -gt -3600

Comentario El sistema estaacute en un uso horario GMT +0100 (meridiano de Madrid-Bruselas-Pariacutes)

_tzname Sintaxis extern char _tzname[2]

Como puede verse se trata de una matriz de punteros a caraacutecter que

representan componentes de la variable de entorno TZ ( 171)

_tzname[0] sentildeala a una cadena de tres caracteres representando el nombre del uso horario

_tzname[1] sentildeala a una cadena de tres caracteres con el nombre de la zona DST (Daylight Daving Time) Si este valor no existe _tzame[1] sentildeala a una cadena nula

En los sistemas Win32 estos valores se obtienen del SO Ejemplo

cout ltlt _tzname[0] -gt PSTcout ltlt _tzname[1] -gt 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 caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

Esta variable se define como un puntero constante a caraacutecter (

421e) Es la versioacuten de caracteres anchos ( 221a1) 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

Maacutes informacioacuten en el capiacutetulo correspondiente de la Libreriacutea Estaacutendar (

551) Ver ejemplo ( 455c)

clock_t Sintaxis typedef long clock_t

Este tipo define el valor devuelto por la funcioacuten clock() definida en lttimehgt que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacioacuten del programa Maacutes informacioacuten en el capiacutetulo

correspondiente de la Libreriacutea Estaacutendar ( 551) Ejemplo ( 91)

Tema relacionado Constantes manifiestas ( 141a)

414 Visibilidad

sect1 Sinopsis

La visibilidad de un identificador es la regioacuten de coacutedigo fuente desde la que se puede legalmente acceder al objeto asociado al identificadorAacutembito 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 aacutembito pero este puede exceder a la visibilidad

sect2 Lo sentildealado en la paacutegina anterior respecto al aacutembito ( 413) significa que tambieacuten hay siete categoriacuteas para la visibilidad de un identificadorsentencia bloque (o local) funcioacuten prototipo de funcioacuten fichero clase y espacio de nombres Sin embargo los maacutes importantes y usuales son de funcioacuten de fichero (global) y de programa

Ejemplo

int i char ch auto por defecto

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

i = 3 int i y char ch en aacutembito y visibles double i i = 30e3 double i en aacutembito y visible int i=3 en aacutembito pero oculto ch = A char ch en aacutembito y visible double i es terminada aquiacute double i fuera de aacutembito i += 1 int i visible i == 4 char ch todaviacutea en aacutembito y visible (ch = A) int i y char ch son terminados aquiacute int i y char ch fuera de aacutembito

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

sect3 Variables locales

Las variables locales o de bloque tienen visibilidad dentro del bloque desde el punto de

declaracioacuten ( 413) hasta el final del mismo De este tipo son las variables automaacuteticas incluyendo los paraacutemetros formales de las funciones Ocultan cualquier otra variable o funcioacuten externas del mismo nombre Por ejemplo

int x yfunc(double x) double y oculta a int y double y visible desde aquiacute fin de visibilidad de double y

Ver tambieacuten 413 Ocultacioacuten

sect4 Variables globales

Las variables globales a un fichero se declaran fuera de cualquier bloque funcioacuten o clase Sintaacutecticamente la declaracioacuten es ideacutentica que la de las variables locales solo cambia la situacioacuten de la declaracioacuten El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de

cada funcioacuten con una declaracioacuten extern de cada variable ( 418d) La regla es

Si la declaracioacuten de una variable externa ocurre antes que su uso en alguna funcioacuten particular entonces no hay necesidad de una

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

declaracioacuten extern de la variable dentro de la funcioacuten

Ejemplo

extern x punto de declaracoacuten de xvoid 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

sect41 El aacutembito de una variable global es desde el punto de declaracioacuten 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 funcioacuten que las invoque (avisar a cada funcioacuten que la variable en cuestioacuten es externa)

Puesto que C++ no permite declaracioacuten de funciones dentro de funciones [1] sus identificadores son globales al fichero en que se han declarado (las funciones tienen aacutembito global) Lo que siacute 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 razoacuten y por comodidad se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actuacutean como repositorios de declaraciones y definiciones que son incluidos

mediante include ( 4910g) al principio de cada fuente (asiacute no se olvida ninguacuten extern) Por esta razoacuten tales ficheros se denominan de cabecera

Nota por una larga tradicioacuten de C las declaraciones de las funciones de las Libreriacuteas

Estaacutendar ( 5) se agrupan en una serie de ficheros de nombres conocidos de los que los correspondientes a las libreriacuteas que se mantienen por compatibilidad con el antiguo C tienen la terminacioacuten h de Header (cabecera en ingleacutes)

Por defecto las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde moacutedulos compilados separadamente) referencian a la

misma entidad es decir tienen enlazado externo ( 144)

sect42 Como se veraacute a continuacioacuten todas las variables globales a un fichero y por este simple hecho tienen duracioacuten estaacutetica

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

Nota aunque desde cierta oacuteptica el empleo de variables globales facilita algunas cosas Por ejemplo hay que pasar menos paraacutemetros a las funciones es mala praacutectica abusar de ellas los programas se hacen difiacuteciles de manejar e interpretar y existe maacutes 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 funcioacuten estaacuten definidos dentro del cuerpo o en su lista de paraacutemetros

sect43 No olvidar que una variable global declarada static ( 418c) solo es visible desde el punto de declaracioacuten hasta el final del fichero y solo en ese fichero Esto es tambieacuten de aplicacioacuten para las funciones

415 Duracioacuten de almacenamiento y ciclo vital

sect1 Duracioacuten de almacenamiento

La duracioacuten de almacenamiento (Storage duration) de un objeto es una propiedad estrechamente relacionada con el tipo de almacenamiento Se define como el miacutenimo 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 fiacutesicamente en memoria Esta propiedad acompantildea al objeto desde el instante de su creacioacuten (definicioacuten) y depende del modo en que se realizoacute esta definicioacuten

Existen tres tipos de duracioacuten de almacenamiento estaacutetica local (o automaacutetica)

y persistente [2] cuyas caracteriacutesticas describimos a continuacioacuten

sect11 Duracioacuten estaacutetica

Tan pronto como se inicia la ejecucioacuten de un programa los objetos con duracioacuten estaacutetica reciben su correspondiente asignacioacuten de memoria [1] que permanece hasta que finaliza el programa Si

no existe ninguacuten iniciador o constructor expliacutecito estos objetos son inicializados a cero o nulo ( 412)

Nota el Estaacutendar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracioacuten estaacutetica

Es importante no confundir el concepto de duracioacuten estaacutetica con visibilidad global o de fichero dado que un objeto puede tener duracioacuten estaacutetica (toda la vida del programa) y aacutembito local a un bloque de coacutedigo a una funcioacuten o a un fichero La contraria siempre es equivalente es decir una variable por el simple hecho de tener visibilidad global tiene duracioacuten estaacutetica

Donde quiera que sean definidas todas las funciones tienen duracioacuten estaacutetica (porque sus identificadores son globales) y como se ha dicho todas las variables globales a un fichero tienen duracioacuten estaacutetica por el simple hecho de ser globales Duracioacuten y visibilidad pueden ser conferidas de forma impliacutecita o expliacutecita La primera simplemente declaraacutendolas fuera de cualquier funcioacuten (generalmente al principio del fichero) La declaracioacuten expliacutecita se efectuacutea mediante el uso de los

modificadores static ( 418c) y extern ( 418d)

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

Nota no olvidar que (desgraciadamente en este sentido el estaacutendar ANSI se presta a confusioacuten) la variable o funcioacuten global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracioacuten 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 palabrastatic ( 4111b Subespacios anoacutenimos)

Los objetos locales de clarados con el especificador static se crean en una zona especial de

memoria el montoacuten o heap ( 132) en el momento en que la ejecucioacuten del programa llega por primera vez a su declaracioacuten A partir de este momento tienen existencia hasta la finalizacioacuten del programa

sect12 Duracioacuten automaacutetica

Los objetos de duracioacuten local tambieacuten conocidos como automaacuteticos tienen una existencia maacutes precaria (que los estaacuteticos) Son creados en la pila o en un registro cuando entra en ejecucioacuten el bloque o funcioacuten y son destruidos automaacuteticamente cuando el programa sale del bloque o funcioacuten

C++ dispone de una palabra clave especiacutefica para este fin auto ( 418a) 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 funcioacuten de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades

En los objetos con duracioacuten local su aacutembito tambieacuten es local al bloque o funcioacuten Pero la inversa no es necesariamente cierta los objetos con aacutembito local pueden tener duracioacuten no automaacutetica

Cuando una variable automaacutetica sale de su aacutembito es llamado impliacutecitamente 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 funcioacutenmain Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores

Ojo cuando un puntero a un objeto sale de aacutembito no es llamado impliacutecitamente ninguacuten destructor para el objeto sentildealado [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 L2 Ok crea un int int pt1 = ampx L3 Ok crea un int int pt2 L4 Ok crea un int pt2 = new(int) L5 Ok crea un int (1)

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

delete pt2 L7 Ok destruido int(1) pt2 L8 Ok destruidos x pt1 y pt2

Los objetos de duracioacuten local deben ser iniciados expliacutecitamente de otro modo su contenido es imprevisible (simplemente basura) [3] Aunque pueden ser declarados expliacutecitamente con el modificador auto hemos sentildealado que es innecesario ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcioacuten

Nota cuando se aplica el especificador de almacenamiento register ( 418b) a la declaracioacuten de variables (por ejemplo int char float) ademaacutes de pasar una peticioacuten al compilador para que caso de ser posible situacutee el objeto en un registro implica tambieacuten duracioacuten automaacutetica (auto)

sect13 Duracioacuten persistente

Los objetos persistentes (tambieacuten llamados dinaacutemicos) son creados y destruidos por llamadas a funciones especiacuteficas Son creados en una reserva especial de memoria conocida

como montoacuten (heap 132) utilizando cualquier funcioacuten de libreriacutea estaacutendar como malloc o el

operadornew ( 4920) La destruccioacuten debe realizarse expliacutecitamente con free o delete ( 4921)

Auacuten a riesgo de ser pelmazos es importante insistir en que salvo que se adopten medidas especiales la destruccioacuten de los objetos persistentes se realiza siempre mediante la utilizacioacuten expliacutecita (por el programador) de las funciones mencionadas Recordar que con estos

objetos no ocurre lo mismo que con los automaacuteticos En aquellos la uacutenica preocupacioacuten del programador es crearlos ya que al salir de aacutembito seraacuten automaacuteticamente destruidos por el compilador Estos en cambio deben ser destruidos expliacutecitamente

sect2 Ciclo vital

El tiempo de vida o ciclo vital (Lifetime) de un objeto es una propiedad de tiempo de ejecucioacuten (Runtime) Viene determinado por el lapso entre su creacioacuten y su destruccioacuten Por supuesto no puede exceder la duracioacuten 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 rehuacutesa la zona de almacenamiento que le habiacutea sido asignada

Nota decimos que un objeto es trivial cuando es por ejemplo un tipo simple preconstruido en el lenguaje En este caso una expresioacuten del tipo

int x

basta para que el compilador pueda reservar espacio de almacenamiento

Observe que el ciclo vital de los objetos automaacuteticos y estaacuteticos es controlado automaacuteticamente por el compilador En los primeros la destruccioacuten se realiza cuando el objeto sale de aacutembito En los

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital

segundos la destruccioacuten ocurre con las rutinas de finalizacioacuten del programa Por su parte el ciclo vital de los objetos dinaacutemicos es controlado por el programador

469

  • 323e Secuencias de escape
    • sect1 Sinopsis
    • sect2 Secuencias de escape
    • sect31 Octal
    • sect5 Trigrafos
      • 323f Constantes de cadena
        • sect1 Sinopsis
        • sect2 Secuencias de escape
        • sect4 Peculiaridades
        • sect6 Concatenacioacuten de cadenas
          • 323g Constantes de enumeracioacuten
            • sect1 Sinopsis
            • sect2 Sintaxis
            • sect3 Descripcioacuten
              • 326 Puntuadores
                • sect1 Sinopsis
                • sect2 Corchetes [ ]
                • sect3 Pareacutentesis ( )
                • sect4 Llaves
                • sect5 Coma
                • sect6 Punto y coma
                • sect7 Dos puntos
                • sect8 Puntos suspensivos
                • sect9 Asterisco
                • sect10 Signo igual =
                • sect11 Almohadilla
                  • 4 Estructura del lenguaje
                    • sect1 Sinopsis
                    • 41 Declaraciones
                      • sect1 Sinopsis
                      • 411 Entidades
                        • sect1 Presentacioacuten
                        • sect2 El papel de las declaraciones
                        • sect3 Atributos
                          • 412 Declaraciones y definiciones
                            • sect1 Sinopsis
                            • sect3 Regla de una sola definicioacuten
                            • sect4 Declaraciones
                            • sect5 Definiciones
                            • sect6 Iniciar
                            • sect7 Reglas de inicio
                            • sect78 Inicio de matrices estructuras y uniones
                            • sect8 Definicioacuten provisional
                              • 413 Aacutembito
                                • sect1 Sinopsis
                                • sect2 Clases de aacutembito
                                • sect21 Aacutembito de Sentencia
                                • sect22 Aacutembito de Bloque
                                • sect23 Aacutembito de Funcioacuten
                                • sect24 Aacutembito de Prototipo
                                • sect25 Aacutembito de Fichero
                                • sect26 Aacutembito de Clase
                                • sect27 Aacutembito de espacio de nombres
                                • sect3 Ocultacioacuten
                                • sect31 Acceso cualificado
                                • sect4 Punto de declaracioacuten
                                • sect5 Acceso a entidades
                                  • 413a Tipos y variables globales
                                    • sect1 Sinopsis
                                    • sect2 Variables y tipos globales maacutes frecuentes
                                      • 414 Visibilidad
                                        • sect1 Sinopsis
                                        • sect3 Variables locales
                                        • sect4 Variables globales
                                          • 415 Duracioacuten de almacenamiento y ciclo vital
                                            • sect1 Duracioacuten de almacenamiento
                                            • sect11 Duracioacuten estaacutetica
                                            • sect12 Duracioacuten automaacutetica
                                            • sect13 Duracioacuten persistente
                                            • sect2 Ciclo vital