Since it's creation by Bjarne Stroustrup, C++ has undergone
extensive changes, specially in more recent years by the C++ Standards
Committee. Several new features have been added to the basic language,
including templates, exception handling, run time type information, and, of
course, namespaces.
You might be inclined to believe that namespaces don't affect you
one way or another unless you decide to use them, but they do. The C++
Standards Committee has basically rewritten the Standard Library, placing most
of its facilities inside a namespace called std
. This change alone
forces changes in existing pre-draft programs that use the SL.
A namespace defines a new scope. Members of a namespace are said
to have namespace scope. They provide a way to avoid name collisions (of
variables, types, classes or functions) without some of the restrictions
imposed by the use of classes, and without the inconvenience of handling nested
classes.
Defining a namespace is similar to defining a class. First goes
the namespace
keyword, followed by the identifier (the namespace
name), followed by member declarations enclosed in braces. For example:
namespace direct {
class Arrow
{
public:
Arrow(int dir);
void setDirection(int dir);
private:
int direction;
}
// ...... other stuff
}
A namespace, however, cannot have access specifiers, such as public:
or private:
. All members of a namespace are public. It cannot have
a trailing semicolon, either. An important difference between classes and
namespaces, is that class definitions are said to be closed, meaning that, once
defined, new members cannot be added to it. A namespace definition is open, and
can be split over several units. For example:
// file SY.h
namespace SY {
class Maker { ... };
class SuperMaker : public Maker { ... };
}
// file data.h
namespace SY {
class Binder { ... };
class DataBinder : public Binder { ... };
}
In this example, there are two files (SY.h
and data.h), both defining namespace SY. The definition of SY on data.h does
not conflict with the one in
SY.h, but actually extends it. If you look
closely at the Standard Library, you'll notice that no single header file
declares all members of namespace std
. Each file only declares
some members, adding them to the global std
namespace.
There are four ways you can refer to namespace members:
std::cout << "Hello Nasty";
using std::cout;
cout << "Hello Nasty";
std::cout
. using namespace std;
cout << "Hello Nasty";
std
namespace X
{
namespace Y
{
class Z { ... };
}
}
X::Y::Z
, but we can declare an alias namespace w = X::Y;
w::Z
.
Note: As you can see, namespaces can be nested. One of the design goals of
namespaces was to encourage programmers and vendors to wrap their libraries
inside them, minimizing name collisions. One particularly useful way of taking
advantage of this is when you are designing libraries for, say, your company,
which involve several pieces of functionality. For example, I keep some of my
reusable system classes and templates in a WRuntime
namespace,
which contains different namespaces inside it like WThreading
and
.
WLogging
Until now, I've only covered named namespaces, but you can
also declare unnamed namespaces. Take for example:
namespace
{
class Car
{
.... // class members here
}
// other members here
}
this definition behaves exactly like:
namespace __UniqueName__
{
class Car
{
.... // class members here
}
// other members here
}
using namespace __UniqueName__;
For each unnamed namespace, the compiler generates a unique name
(represented here by __UniqueName__), which differs from every other
name in the program. You might be asking yourself, What's the use of this?
Let's see the example above. Class Car is defined in an unnamed
namespace declared at global scope, thus, it can be referred to as if it were
declared directly at global scope. However, since it's a member of an unnamed
namespace, the compiler mangles its name with the generated namespace name, so
it won't conflict with other names.
Unnamed namespaces can also be defined inside other namespaces.
Suppose the unnamed namespace in the example above was declared inside
namespace foo
. Then class Car could be referred to as foo::Car
.
Notice there's no mention of the unnamed namespace, but the link name for Car
will still be mangled with namespace foo and the unique name generated for the
unnamed namespace by the compiler.
An interesting use of unnamed namespaces is hiding names inside
modules. Before, this would be done using the static
keyword, but
the new C++ Standard reads in section 7.3.1.1 Unnamed Spaces, paragraph 2:
"The use of the static keyword is deprecated when declaring objects in a
namespace scope, the unnamed namespace provides a superior alternative."
static
, when applied atstatic
onlyPersonally, I feel that, while unnamed namespaces are a far better solution
than static to this problem, it's not the best that could have been
implemented. To me, using unnamed namespaces in this way seem to be too much
like taking advantage of a "side" effect of the lack of name of the namespace.
I would feel much more comfortable with an appropriately named keyword to
accomplish this behavior (think hidden
or internal
),
but then again, I'm no language lawyer, nor am I completely informed of the
reasons why the committee chose it that way.
Namespaces are a powerful addition to an already powerful
language, giving the programmer more flexibility, provided he knows how to take
advantage of it. Please consider the use of namespaces carefully when planning
your next project, you might be surprised at how useful they can be.