Namespaces

Introduction

Consider the following problem -- suppose you are a library author and you write a class called String. That's fine and good -- until your software uses another library, which also includes a class called String.

The problem is inevitable, because there are certain names for classes that are likely to be used. For example, String, Exception, Matrix, Array, and so forth. There is the same problem with function names and global constants -- for example, what's the chance of two library authors using a global constant called SIZE ? Namespaces are a common way of addressing this problem.

How Namespaces Work

It's common for two people to have a name in common -- how many people are called John, Daniel, Chris, or moving to last names, Smith, Patel, Wang, or Martinez ? Names are likely to collide, it's inevitable. But the fact that everyone has more than one name helps somewhat. For example, someone by the name of ``John Gilbert'' can style himself ``John E. Gilbert'', and adding the middle initial to the mix helps avoid confusion. Namespaces amount to a similar strategy.

Namespace Declarations

A namespace is a family name for C++ identifiers. Several identifiers and classes can live under the same namespace, this way package authors can write an entire package and the only use up one name in the global namespace (the namespace itself). Namespaces are declared using a namespace declaration, using the following syntax:

namespace foo 
{
	const int x;
	void bar();
} // no semicolon required
	

To make it easier to put several different class names within the same name space, one may ``add'' members to an existing namespace with multiple declarations:

namespace foo
{
	int x;
}
// more code

namespace foo // legal 
{
	int y; // now x and y are *both* in the namespace foo.
}
	

Name Resolution

Variables declared in a namespace must be referred to by their full name -- the name of the namespace, followed by the operator :: followed by their name within the namespace. For example, we'd refer to the variable x above as foo::x.

Using Declarations

One doesn't refer to family members by their family names, and usually they don't refer to friends by more than one name. Likewise, it's often convenient to tell the compiler that we're using a namespace, so that we don't have to fully qualify names. The syntax is as follows:

>
using namespace foo;	// now all members of the namespace foo are visible
   
Sometimes, it's an overkill to make everything in a namespace visible, and it's better to only make select members visible. We can also do that:
using foo::x;	// now foo::x is visible but foo::y is not.

An Example

We recap these concepts with a simple example:

namespace1.cc


#include <iostream.h>

namespace foo 
{
	void f() { cout << "calling foo::f()" << endl; }
	void g() { cout << "calling foo::g()" << endl; }
}

namespace bar 
{
	void f();
}

// since we provide the definition outside the namespace, we need to use
// the scope resolution operator to make it clear which namespace we
// are talking about.

void bar::f() { cout << "calling bar::f()" << endl; }

namespace blah
{
	void f() { cout << "calling blah::f()" << endl; }
}

int main()
{

	// call the version of f() in namespace foo
	foo::f();	

	// call the version of f() in namespace bar
	bar::f();	

	// makes all functions in namespace blah visible without qualification.
	using namespace blah;	

	// This calls blah::f()
	f();

	// makes foo::g() visible, but other elements in namespace foo
	// are invisible.
	using foo::g;

	// foo::g()
	g();

	// blah::f() again, since the other declaration leaves foo::f() hidden.
	f();

	return 0;

}

Namespaces And The Standard Library

The standard library uses namespaces extensively, so that the standard predefined functions do not ``pollute'' the global namespace. All standard library functions lie under the namespace by the name of std. For short programs, it is often convenient to begin with the declaration

using namespace std;

However, for longer programs, it is better to just make using declarations for frequently used classes and objects. For example, the following declarations are commonly used:

using std::cout;
using std::cin;
using std::endl;
	

Of course, if you are writing your own header file, you shouldn't place any using declarations in the header file, because it would result in a flood of available names and potential clashes with the users code, and the user might not be very happy with that!