4.1.4 Visibilidad
§1 Sinopsis
La visibilidad de un identificador es la región de código fuente desde la que se puede legalmente acceder al objeto asociado al identificador. Ámbito y visibilidad coinciden generalmente, si bien pueden darse circunstancias en que un objeto puede aparecer oculto (invisible) temporalmente debido a la presencia de un identificador duplicado. El objeto existe, pero el identificador original no puede ser utilizado para accederlo hasta que el identificador duplicado es terminado.
Nota: la visibilidad no puede exceder al ámbito, pero este puede exceder a la visibilidad.
§2 Lo señalado en la página anterior respecto al ámbito (
4.1.3) significa que también hay siete categorías para la visibilidad de un
identificador: sentencia; bloque (o local); función; prototipo de función; fichero;
clase y espacio de nombres. Sin embargo, los más importantes y usuales son: de función; de fichero
(global), y de programa.
Ejemplo:
...
{
int i; char ch; // auto por defecto
i = 3; // int i y char ch, en ámbito y visibles
...
{
double i;
i = 3.0e3; // double i en ámbito y visible
// int i=3 en ámbito pero oculto
ch = 'A'; // char ch en ámbito y visible
} // double i es terminada aquí
// double i fuera de ámbito
i += 1; // int i visible, i == 4
...
// char ch todavía en ámbito y visible (ch = 'A')
} // int i y char ch
son terminados aquí
...
// int i y char ch fuera de ámbito
Respecto a este asunto de la visibilidad, veremos que se aplican reglas especiales para los nombres de clases y miembros
ocultos de clase. Bajo ciertas condiciones, los operadores de acceso
permiten acceder identificadores ocultos cuando son miembros de clase.
§3 Variables locales
Las variables locales o de bloque, tienen visibilidad dentro del bloque, desde el punto de declaración
( 4.1.3) hasta
el final del mismo. De este tipo son las variables automáticas, incluyendo los parámetros formales de las funciones.
Ocultan cualquier otra variable o función externas del mismo nombre. Por ejemplo:
int x, y;
func(double x) {
double y; // oculta a int y
... // double y
visible desde aquí
} // fin de visibilidad de double y
Ver también 4.1.3
Ocultación.
§4 Variables globales
Las variables globales a un fichero se declaran fuera de cualquier bloque, función o clase. Sintácticamente la
declaración es idéntica que la de las variables locales, solo cambia la situación de la declaración. El hecho de colocarlas al
principio evita tener que hacerlas visibles dentro de cada función con una declaración extern de cada variable
( 4.1.8d). La regla es:
Si la declaración de una variable externa ocurre antes que su uso en alguna función particular, entonces no hay necesidad de una declaración extern de la variable dentro de la función. |
Ejemplo:
extern x; // punto de declaracón de
x
...
void
func1(int y) {
x = x+y; // correcto x es visible
}
void func2(int y) {
z = z+y; // incorrecto z no es visible
extern z;
z = z+y; // correcto z es ahora visible
}
§4.1 El ámbito de una variable global es desde el punto de declaración 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 función que las invoque (avisar a cada función que la variable en cuestión es externa).
Puesto que C++ no permite declaración de funciones dentro de funciones [1], sus identificadores son globales al fichero en que se han declarado (las funciones tienen ámbito global). Lo que sí se permite son prototipos de funciones dentro de otras funciones que las invocan (los prototipos son declaraciones, no definiciones).
Por supuesto, si las variables globales a un fichero deben ser vistas desde otros ficheros, es necesario declararlas al
principio como extern (en los otros ficheros). Por esta razón y por comodidad, se acostumbra a agrupar todas las
declaraciones de variables y funciones externas en unos ficheros que actúan como "repositorios" de declaraciones y definiciones
que son incluidos mediante #include (
4.9.10g) al principio de cada fuente (así no se olvida ningún "extern"). Por esta razón tales
ficheros se denominan "de cabecera".
Nota: por una larga tradición de C, las declaraciones de las funciones de las
Librerías Estándar ( 5)
se agrupan en una serie de ficheros de nombres conocidos, de los que los correspondientes a las librerías que se mantienen por
compatibilidad con el antiguo C tienen la terminación .h, de "Header" (cabecera en inglés).
Por defecto, las variables externas y las funciones tiene la propiedad de que todas las referencias a sus
nombres (incluso desde módulos compilados separadamente), referencian a la misma entidad, es decir, tienen enlazado externo
( 1.4.4).
§4.2 Como se verá a continuación, todas las variables globales a un fichero y por este simple hecho,
tienen duración estática.
Nota: aunque desde cierta óptica, el empleo de variables globales facilita algunas cosas. Por ejemplo, hay que pasar menos parámetros a las funciones, es mala práctica abusar de ellas, los programas se hacen difíciles de manejar e interpretar y existe más 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 función están definidos dentro del cuerpo o en su lista de parámetros.
§4.3 No olvidar que una variable global declarada static
( 4.1.8c) solo es visible desde el punto
de declaración hasta el final del fichero y solo en ese fichero. Esto es también de
aplicación para las funciones.
[1] Precisamente, la introducción de objetos en C++, que permite englobar juntas variables y funciones, viene a paliar en cierta forma esta limitación.