Puede referirse a un nombre dentro de un espacio de nombres de
tres maneras diferentes: especificando el nombre utilizando el
operador de resolución de ámbito, con una directiva
using
que introduzca todos los nombres en el espacio
de nombres o mediante una declaración using
para
introducir nombres de uno en uno.
Cualquier nombre en un espacio de nombres puede ser explícitamente especificado utilizando el operador de resolución de ámbito de la misma forma que puede referirse a los nombres dentro de una clase:
//: C10:ScopeResolution.cpp namespace X { class Y { static int i; public: void f(); }; class Z; void func(); } int X::Y::i = 9; class X::Z { int u, v, w; public: Z(int i); int g(); }; X::Z::Z(int i) { u = v = w = i; } int X::Z::g() { return u = v = w = 0; } void X::func() { X::Z a(1); a.g(); } int main(){} ///:~
Listado 10.9. C10/ScopeResolution.cpp
Nótese que la definición X::Y::i
puede
referirse también a un atributo de la clase
Y
anidada dentro de la clase
X
en lugar del espacio de nombres
X
.
Puesto que teclear toda la especificación para un
identificador en un espacio de nombres puede resultar
rápidamente tedioso, la palabra clave using
le
permite importar un espacio de nombres entero de una vez.
Cuando se utiliza en conjunción con la palabra clave
namespace
, se dice que utilizamos una directiva
using
. Las directivas
using
hacen que los nombres actúen como si
perteneciesen al ámbito del espacio de nombres que les
incluye más cercano por lo que puede utilizar
convenientemente los nombres sin explicitar completamente su
especificación. Considere el siguiente espacio de nombres:
//: C10:NamespaceInt.h #ifndef NAMESPACEINT_H #define NAMESPACEINT_H namespace Int { enum sign { positive, negative }; class Integer { int i; sign s; public: Integer(int ii = 0) : i(ii), s(i >= 0 ? positive : negative) {} sign getSign() const { return s; } void setSign(sign sgn) { s = sgn; } // ... }; } #endif // NAMESPACEINT_H ///:~
Listado 10.10. C10/NamespaceInt.h
Un uso de las directivas using
es incluir todos los
nombres en Int
dentro de otro espacio de
nombres, dejando aquellos nombres anidados dentro del
espacio de nombres
//: C10:NamespaceMath.h #ifndef NAMESPACEMATH_H #define NAMESPACEMATH_H #include "NamespaceInt.h" namespace Math { using namespace Int; Integer a, b; Integer divide(Integer, Integer); // ... } #endif // NAMESPACEMATH_H ///:~
Listado 10.11. C10/NamespaceMath.h
También puede declarar todos los nombres en
Int
dentro de la función pero dejando
esos nombres anidados dentro de la función:
//: C10:Arithmetic.cpp #include "NamespaceInt.h" void arithmetic() { using namespace Int; Integer x; x.setSign(positive); } int main(){} ///:~
Listado 10.12. C10/Arithmetic.cpp
Sin la directiva using
, todos los nombres en el
espacio de nombres requerirían estar completamente
explicitados.
Hay un aspecto de la directiva using
que podría
parecer poco intuitivo al principio. La visibilidad de los
nombres introducidos con una directiva using
es el
rango en el que se crea la directiva. Pero ¡puede hacer caso
omiso de los nombres definidos en la directiva
using
como si estos hubiesen sido declarados
globalmente para ese ámbito!
//: C10:NamespaceOverriding1.cpp #include "NamespaceMath.h" int main() { using namespace Math; Integer a; // Hides Math::a; a.setSign(negative); // Now scope resolution is necessary // to select Math::a : Math::a.setSign(positive); } ///:~
Listado 10.13. C10/NamespaceOverriding1.cpp
Suponga que tiene un segundo espacio de nombres que contiene
algunos nombres en namespace Math
:
//: C10:NamespaceOverriding2.h #ifndef NAMESPACEOVERRIDING2_H #define NAMESPACEOVERRIDING2_H #include "NamespaceInt.h" namespace Calculation { using namespace Int; Integer divide(Integer, Integer); // ... } #endif // NAMESPACEOVERRIDING2_H ///:~
Listado 10.14. C10/NamespaceOverriding2.h
Dado que este espacio de nombres también se introduce con
una directiva using
, existe la posibilidad de tener
una colisión. De todos modos, la ambigüedad aparece en el
momento de utilizar el nombre, no en la directiva
using
:
//: C10:OverridingAmbiguity.cpp #include "NamespaceMath.h" #include "NamespaceOverriding2.h" void s() { using namespace Math; using namespace Calculation; // Everything's ok until: //! divide(1, 2); // Ambiguity } int main() {} ///:~
Listado 10.15. C10/OverridingAmbiguity.cpp
Por tanto, es posible escribir directivas using
para introducir un número de espacios de nombre con nombres
conflictivos sin producir ninguna ambigüedad.
Puede inyectar nombres de uno en uno en el ámbito actual
utilizando una declaración using
. A diferencia de
la directiva using
, que trata los nombres como si
hubiesen sido declarados globalmente para ese ámbito, una
declaración using
es una declaración dentro del
ámbito actual. Eso significa que puede sobrescribir nombres
de una directiva using
:
//: C10:UsingDeclaration.h #ifndef USINGDECLARATION_H #define USINGDECLARATION_H namespace U { inline void f() {} inline void g() {} } namespace V { inline void f() {} inline void g() {} } #endif // USINGDECLARATION_H ///:~
Listado 10.16. C10/UsingDeclaration.h
La declaración using
simplemente da el nombre
completamente especificado del identificador pero no da
información de tipo. Eso significa que si el espacio de
nombres contiene un grupo de funciones sobrecargadas con el
mismo nombre, la declaración using
declara todas
las funciones pertenecientes al grupo sobrecargado.
Es posible poner una declaración using
en cualquier
sitio donde podría ponerse una declaración normal. Una
declaración using
funciona de la misma forma que
cualquier declaración normal salvo por un aspecto: puesto
que no se le da ninguna lista de argumentos, una declaración
using
puede provocar la sobrecarga de una función
con los mismos tipos de argumentos (cosa que no está
permitida por el procedimiento de sobrecarga normal). De
todas formas, esta ambigüedad no se muestra hasta el momento
de uso, no apareciendo en el instante de declaración.
Una declaración using
puede también aparecer dentro de un
espacio de nombres y tiene el mismo efecto que en cualquier otro
lugar (ese nombre se declara dentro del espacio):
//: C10:UsingDeclaration2.cpp #include "UsingDeclaration.h" namespace Q { using U::f; using V::g; // ... } void m() { using namespace Q; f(); // Calls U::f(); g(); // Calls V::g(); } int main() {} ///:~
Listado 10.17. C10/UsingDeclaration2.cpp
Una declaración using
es un alias. Le permite declarar la
misma función en espacios de nombres diferentes. Si acaba
redeclarando la misma función importando diferentes espacios de
nombres no hay problema, no habrá ambigüedades o duplicados.