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 cierto 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 fabricantes 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). No es una solución elegante ni respaldada por el lenguaje.

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 con respecto a class, struct, enum y union:

  • Una definición de namespace solamente puede aparecer en el ámbito global o anidada dentro de otro espacio de nombres.

  • 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 ficheros 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


Es posible crear alias de un namespace de forma que no hace falta que teclee un enrevesado nombre creado por algún fabricante 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 añadir elementos escribiendo «namespace» sin ningún identificador.

Los nombres en este espacio están disponibles automáticamente en esa unidad de traducción sin calificación. Se garantiza que un espacio sin nombre es único para cada unidad de traducción. Si usted pone nombres locales en un espacio de nombres sin nombre, no necesitará darles enlazado interno con static.

C++ desaconseja el uso de estáticos a fichero en favor de los espacios de nombres sin nombre.

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.