Topic : C++ Namespaces
Author : Tomas Rest
Page : 1

C++ namespaces
by Tomas Restrepo


Introduction
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 it's facilities inside a namespace called std. This change alone forces changes in existing pre-draft programs that use the SL.

But, What's a namespace, really?
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 (name.h and data.h), both defining namespace SY. The definition of SY on data.h does not conflict with the one in name.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.

Using Namespaces
There are four ways you can refer to namespace members:

Using the full member name, including the namespace it belongs to. For example:

  std::cout << "Hello Nasty";
   
Note: Remember that on Pre-Draft days, cout was not declared in any namespace (they didn't exist yet, anyway), and header files used an .h suffix.
By taking advantage of Using-Declarations, as in

  using std::cout;
  cout << "Hello Nasty";

   
this declares cout in the current scope as synonym for std::cout.
By taking advantage of Using-Directives, as in

  using namespace std;
  cout << "Hello Nasty";

   
which specifies that the current scope can refer to names in the std namespace without using full qualifiers. This is mostly used when porting legacy code.
Using aliases. Say, for example, I have

  namespace X
  {
    namespace Y
    {
      class Z { ... };
    }
  }

   
The full qualifier for Z is X::Y::Z, but we can declare an alias using

  namespace w = X::Y;
   
This declares w as an alias for namespace X::Y, thus we can access Z using 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.
Unnamed Namespaces
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."
In case you've forgotten (or didn't know), static, when applied at namespace scope, specifies internal linkage. However, static only applies to names of objects, functions and anonymous unions, not to type declarations.

Personally, 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.

Conclusion
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.


Page : 1