10.2. Espacios de nombres

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.

10.2.1. Crear un 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.

Espacios de nombres sin nombre

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.

Amigas

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.