Pese a que los nombres pueden estar anidados dentro de clases,
los nombres de funciones globales, variables globales y clases
se encuentran incluidos dentro de un único espacio de
nombres. La palabra reservada static
le da control
sobre éste permitiéndole darle tanto a variables como a
funciones enlazado interno (es decir convirtiéndolas en
estáticas al fichero). Pero en un proyecto grande, la falta de
control sobre el espacio de nombres global puede causar
problemas. Con el fin de solventar esos problemas para clases,
los programadores suelen crear nombres largos y complicados que
tienen baja probabilidad de crear conflictos pero que suponen
hartarse a teclear para escribirlos. (Para simplificar este
problema se suele utilizar typedef
). Pese a que el
lenguaje la soporta, no es una solución elegante.
En lugar de eso puede subdividir el espacio de nombres global en
varias partes más manejables utilizando la característica
namespace
de C++. La palabra reservada
namespace
, de forma similar a class
,
struct
, enum
y union
, sitúa los
nombres de sus miembros en un espacio diferente. Mientras que
las demás palabras reservadas tienen propósitos adicionales, la
única función de namespace
es la de crear un nuevo
espacio de nombres.
La creación de un espacio de nombres es muy similar a la creación de una clase:
//: C10:MyLib.cpp namespace MyLib { // Declarations } int main() {} ///:~
Listado 10.5. C10/MyLib.cpp
Ese código crea un nuevo espacio de nombres que contiene las
declaraciones incluidas entre las llaves. De todas formas,
existen diferencias significativas entre class
,
struct
, enum
y union
:
Una definición con namespace solamente puede aparecer en un rango global de visibilidad o anidado dentro de otro namespace.
No es necesario un punto y coma tras la llave de cierre para finalizar la definición de namespace.
Una definición namespace puede ser "continuada" en múltiples archivos de cabecera utilizando una sintaxis que, para una clase, parecería ser la de una redefinición:
//: C10:Header1.h #ifndef HEADER1_H #define HEADER1_H namespace MyLib { extern int x; void f(); // ... } #endif // HEADER1_H ///:~
Listado 10.6. C10/Header1.h
El posible crear alias de un namespace
de forma que
no hace falta que teclee un enrevesado nombre creado por algún
frabricante de librerías:
//: C10:BobsSuperDuperLibrary.cpp namespace BobsSuperDuperLibrary { class Widget { /* ... */ }; class Poppit { /* ... */ }; // ... } // Too much to type! I'll alias it: namespace Bob = BobsSuperDuperLibrary; int main() {} ///:~
Listado 10.7. C10/BobsSuperDuperLibrary.cpp
No puede crear una instancia de un namespace
tal y
como puede hacer con una clase.
Cada unidad de traducción contiene un espacio de nombres sin
nombre al que puede referirse escribiendo
«namespace
» sin ningún
identificador.
Los nombres en este espacio están disponibles
automáticamente en esa unidad de traducción sin
cualificación. Se garantiza que un espacio sin nombre es
único para cada unidad de traducción. Si usted asigna
nombres locales en un espacio de nombres no necesitará
darles enlazado interno con static
.
En C++ es preferible utilizar espacios de nombres sin nombre que estáticos a fichero.
Es posible añadir una declaración tipo friend
dentro de un espacio de nombres incluyéndola dentro de una
clase:
//: C10:FriendInjection.cpp namespace Me { class Us { //... friend void you(); }; } int main() {} ///:~
Listado 10.8. C10/FriendInjection.cpp
Ahora la función you()
es un miembro
del espacio de nombres Me
.
Si introduce una declaración tipo friend
en una
clase dentro del espacio de nombres global, dicha
declaración se inyecta globalmente.