Professional Documents
Culture Documents
Namespaces
Although names can be nested inside classes, the names of global
functions, global variables, and classes are still in a single global
name space. The static keyword gives you some control over this
by allowing you to give variables and functions internal linkage
(that is, to make them file static). But in a large project, lack of
control over the global name space can cause problems. To solve
these problems for classes, vendors often create long complicated
names that are unlikely to clash, but then you’re stuck typing those
names. (A typedef is often used to simplify this.) It’s not an elegant,
language-supported solution.
You can subdivide the global name space into more manageable
pieces using the namespace feature of C++. The namespace
keyword, similar to class, struct, enum, and union, puts the names
of its members in a distinct space. While the other keywords have
additional purposes, the creation of a new name space is the only
purpose for namespace.
Creating a namespace
The creation of a namespace is notably similar to the creation of a
class:
//: C10:MyLib.cpp
namespace MyLib {
// Declarations
}
int main() {} ///:~
//: C10:Header1.h
#ifndef HEADER1_H
#define HEADER1_H
namespace MyLib {
extern int x;
void f();
// ...
}
//: C10:BobsSuperDuperLibrary.cpp
namespace BobsSuperDuperLibrary {
class Widget { /* ... */ };
Unnamed namespaces
Each translation unit contains an unnamed namespace that you can
add to by saying “namespace” without an identifier:
//: C10:UnnamedNamespaces.cpp
namespace {
class Arm { /* ... */ };
class Leg { /* ... */ };
class Head { /* ... */ };
class Robot {
Arm arm[4];
Leg leg[16];
Head head[3];
// ...
} xanthan;
int i, j, k;
}
int main() {} ///:~
Friends
You can inject a friend declaration into a namespace by declaring it
within an enclosed class:
Using a namespace
You can refer to a name within a namespace in three ways: by
specifying the name using the scope resolution operator, with a
using directive to introduce all names in the namespace, or with a
using declaration to introduce names one at a time.
Scope resolution
Any name in a namespace can be explicitly specified using the
scope resolution operator in the same way that you can refer to the
names within a class:
//: 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();
//: 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; }
// ...
};
One use of the using directive is to bring all of the names in Int into
another namespace, leaving those names nested within the
namespace:
//: 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 ///:~
You can also declare all of the names in Int inside a function, but
leave those names nested within the function:
//: C10:Arithmetic.cpp
#include "NamespaceInt.h"
void arithmetic() {
using namespace Int;
Integer x;
x.setSign(positive);
}
int main(){} ///:~
Without the using directive, all the names in the namespace would
need to be fully qualified.
//: C10:NamespaceOverriding1.cpp
#include "NamespaceMath.h"
//: C10:NamespaceOverriding2.h
#ifndef NAMESPACEOVERRIDING2_H
#define NAMESPACEOVERRIDING2_H
#include "NamespaceInt.h"
namespace Calculation {
using namespace Int;
Integer divide(Integer, Integer);
// ...
}
#endif // NAMESPACEOVERRIDING2_H ///:~
//: 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() {} ///:~
//: 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 ///:~
//: C10:UsingDeclaration1.cpp
#include "UsingDeclaration.h"
void h() {
using namespace U; // Using directive
using V::f; // Using declaration
f(); // Calls V::f();
U::f(); // Must fully qualify to call
}
int main() {} ///:~
The using declaration just gives the fully specified name of the
identifier, but no type information. This means that if the
namespace contains a set of overloaded functions with the same
name, the using declaration declares all the functions in the
overloaded set.
//: 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() {} ///:~