Department of Engineering

IT Services

C++ Namespaces

Namespaces - the concept

The idea of namespaces is quite common in computing languages. A namespace is like a context which determines the meaning of a symbol (if you think of it as a space where names are stored, you won't be too far wrong). Just as the meaning of "Cambridge" will change depending on whether you're in a UK or US context, so the variable accessed in a C++ program by the symbol "i" will depend on the context.

Some simple languages only have one namespace - all function names, variable names, etc belong to the same context. Some other languages have several independent namespaces (one for variable names, one for function names, etc) making it possible to have both a variable and function with the same name, but the number and role of these namespaces are fixed.

C++ has some fixed namespaces, but it also has named namespaces and lets the user create new namespaces. It also offers control over which of these named namespaces will be used when the meaning of a symbol is required.

In order to reduce the risk of name-clashes (2 things with the same name) and errors caused by inadvertently referring to global variables, it helps to restrict the number of consulted namespaces as much as possible (as an analogy consider how "Number 44" might work ok in the context of your street, but in the context of Cambridge it's confusing). The larger the program the more useful this idea is, especially if you use libraries written by other people.

C++ has various mechanisms to control scope and visibility - for example local variables in a function and private members of an object are hidden from the outside world. The C++ namespace keyword offers a further option, so that contexts can be named and entities can be added these contexts. As we'll see later, the notation's rather like that used for classes.

Stroustrup, the author of C++, says that namespaces are a "very fundamental and relatively simple" concept, but you might find some of the later examples on the page difficult. Don't worry - as long as you can make use of the standard namespace, you should be ok.

The C++ standard namespace

In ANSI C++ the standard library facilities (like cout, string, etc) are kept inside the namespace called std, which by default isn't consulted. There are various ways to access the things inside the std namespace -

  • Explicitly mention the namespace each time you use a facility - by using std::cout, etc. This makes your intentions precise, and is the form that the textbooks tend to favour in their initial examples, but it does make the code verbose.
  • Use "using namespace std" inside each function where standard library facilities are used - this will make the standard library facilities available throughout the function: the using directive follows the usual scoping rules. Alternatively you can make specific facilities available - e.g. "using std::cout" lets you use "cout ..." rather than "std::cout ...", but it still doesn't let you use "string ..."
  • Use "using namespace std" at the top of each file, outside of any function - this will make the standard library facilities available throughout the program. We use this approach at CUED for smaller teaching programs. However, it does make globally visible a lot of function and variable names that you're probably not going to use. For example, we use a graphics include file that defines a value RED. Unfortunately RED is also defined in the std namespace, thus causing a potential name-clash when a global "using namespace std" is used.
    For big programs it's probably better not to use this option.

User-defined namespaces

The std namespace is available on any ANSI C++ compiler, but you can make up your own as well. Namespaces resemble classes that have no functionality and have only public members. Whereas with a class new members cannot be added to it after it's been defined, a namespace definition is said to be open, and can be added to. This makes namespaces a useful way to group together elements that are spread across several files. You could for example have 2 versions of some routines: a version in a basic namespace and an alternative version in an experimental namespace. By switching between "using namespace basic" and "using namespace experimental" you can cleanly switch between the 2 versions.

Entities are put into a namespace by doing something like

namespace test {
  int i;
  int j;
}

Then test::i (the same notation that you'd use were test an object) will access the i variable. The command "using namespace test" will make all the entities in the namespace available for the rest of the unit that the statement is in, without the "test::" being necessary. Having created the test namespace as above, you make parts of it visible as follows

void fun() {
  using test::i;
  // Note that in the next line the 'i' of test is used. 'j' isn't visible.
  std::cout << i << std::endl;
}

Name clashes

If you have a local integer with the same name as a global integer, then the local variable simply masks the global one - it's not an error. Neither is it an error to have 2 sufficiently different types of things with the same name - you can't have a string and an integer with the same name in the same function, but the following (which uses i for 2 different purposes) is legal, neither usage interfering with the other.

int main()
{
  class  i {int j;};
  enum  letter {i, j};
  letter l=i;

  return 0;
}

There are cases where the compiler gives an error message when it can't resolve the situation. Some of the rules are rather technical, and only come into play in artificial situations. If you pick sensible names for things you're unlikely to encounter problems.

The following (artificial!) program illustrates some potential sources of conflict. Though it uses many i symbols it compiles on our system without error. The comments show some conflicts which would cause trouble. It might be worth trying to compile the code with and without the changes to see what your compiler says.

#include <iostream>
using namespace std;

namespace extra {
  int i;
}

void i(){
  // Compilation would fail were the next line "using extra::i"
  using namespace extra;

  int i; // this i masks the i in the 'extra' namespace
  i=9;
  cout << i << endl;
}

int main()
{
  enum  letter { i, j};
  // Compilation would fail were the next line "class i { letter i; };"
  class i { letter j; };

  // Can you create an object called 'j' of type i by doing "i j;" ?

  // Compilation would fail were the next line "i();"
  ::i();
  return 0;
}

Local details

On CUED's HP-UX teaching system, you need to use the compiler's "-AA" option (the xcc program does this by default), and the versions of the standard include files that don't have .h on the end of their names. If you used <fstream.h> you'll probably need to replace it by including both <fstream> and <iostream>, but for other include files there's a one-for-one substitution. Note also that - "Objects and libraries compiled with -AA are binary incompatible with objects and libraries compiled without -AA".

On our linux systems "g++" should work fine with the versions of the standard include files that don't have .h on the end of their names

Scope and visibility - a note

The scope of a declaration is the region of source code over which that declaration is active. A variable might not be visible even in situations where its declaration is active - it might be masked by a local variable.