- Libraries Shared Across Languages
- Namespaces in C++
- The System Namespace
- Other Useful Namespaces
- In Brief
Namespaces are a C++ feature designed to eliminate name conflicts, such as having two classes, each in different libraries, called String. Before namespaces were added to the language, library developers tried to make their names unique by adding letters to them: One developer's string class might be called GCString, whereas another developer might call it TKString, the string class in MFC is called CString, and so on. This approach is ugly and reduces, but doesn't prevent, name conflicts.
With namespaces, classes can have simple names. Name conflicts are much less likely, because in addition to a short or local name, classes have a fully qualified name that includes their namespace. Here's a slightly artificial example (normally namespaces are used in separate libraries, not jumbled together in one piece of code like this) that illustrates how they work:
namespace One { class Common { private: int x; public: Common(int a): x(a) {} int getx() {return x;} }; void Do() { Common c(3); Console::WriteLine(__box(c.getx())); } } namespace Two { class Common { private: double d1, d2; public: Common(double param1) : d1(param1),d2(param1) {} double getd1() {return d1;} double getd2() {return d2;} }; void Do() { Common c(3); String* output = String::Concat(__box(c.getd1()), S" " , __box(c.getd2())); Console::WriteLine(output); } } int _tmain() { //Common c(3); // ambiguous One::Common c1(3); Two::Common c2(3); //Do(); //ambiguous One::Do(); Two::Do(); return 0; }
This code defines two namespaces, named One and Two. In each namespace there is a class called Common and a function called Do(). Inside the namespace, there's no problem referring to Common just using its short or local name. The two Do() functions accomplish this without error; each is working with the Common class from its own namespace.
The main function, _tmain(), cannot refer to Common or to Do() using a short name. (The two lines of code commented out in _tmain() cause compiler errors.) It has to use the fully qualified name: the namespace name and the class name, separated by the scope-resolution operator (::).
A using statement allows you to refer to a class with only its short name. It does not cause the compiler or linker to include any files that otherwise wouldn't have been included in your build; it's just a convenience to reduce typing. The example main function can be rewritten as
using namespace One; int _tmain() { Common c1(3); Two::Common c2(3); Do(); Two::Do(); return 0; }
Modern class libraries are each in their own namespacefor example, the templates in the Standard Template Library are in the namespace std. The developers of the .NET Framework built on this concept, dividing the class libraries into namespaces and sub-namespaces. This makes them easier to learn and document.
To use a class in a namespace, you have two choices:
Call the class by its full name (such as System::Math) whenever you're using it:
x = System::Math::PI / 4; System::String* s = new System::String("hello");
Add a using statement at the top of the file, and then call the class by its name within the namespace:
using namespace System; ... x = Math::PI / 4; String* s = new String("hello");
Punctuation: Using . or ::
In most other .NET languages, the punctuation between the namespace name and the class name is a dot (.). For example, in both Visual Basic and C#, a developer would type System.Math.PI. But in C++, you use a double colon (::), called the scope-resolution operator. In the documentation, if you see a reference to System.Something, you just need to change it to System::Something in your code. Use the scope-resolution operator between namespace and sub-namespace, namespace and class, or sub-namespace and class.
As always, you use the dot between the name of an object and an ordinary member function, and the scope-resolution operator between the name of the class and a static member function or variable. In the previous examples, PI is a static member variable of the Math class. In other .NET languages, the punctuation between class or object name and function is always a dot, even when the function is static. This can make the documentation confusing. Most occurrences of . in the documentation should be changed to ::.
IntelliSense, the feature that pops up lists for you to choose from as you type, really helps with this confusion. If you type "System." into a file of C++ code, no list appears and the status bar reads
IntelliSense: 'Could not resolve type for expression to the left of . or ->'
On the other hand, if you type "System::", a list of namespaces and classes appears for you to choose from. Use the lack of feedback from IntelliSense as an indicator that you have typed the wrong thing, and you'll find working from the documentation a lot less confusing.
The second choice is a better approach when you're going to be typing class names from the namespace a number of times, because it saves you typing the namespace name repeatedly. I prefer the first choice when I'm only typing a class name once, because the fuller name gives more clues to a maintainer about what the code is doing. This is even more important when you're using classes from more obscure namespaceseveryone uses classes from System and is familiar with many of them, but the System::Web::Security namespace, for example, might not be so obvious to you or to those who will maintain your code.
Whether you choose to add a using statement to your file or not, you must add a #using directive to the top of your source file. When you create a new .NET project, one of these directives is added for you automatically:
#using <mscorlib.dll>
This gives you access to all the classes that are directly under the System namespace, such as the System::Math class used in these examples. The documentation for the classes that are in sub-namespaces of System includes a line like this one, from System::Xml.Document:
Assembly: System.XML.dll
This is a clue that you need to add this line to your file:
#using <System.XML.dll>
Don't worry about what seem to be extra dots in the filename, and don't change dots to :: here. If you will be using a particular assembly in every file within a project, you can add a reference to the assembly instead (right-click References in Solution View and choose Add Reference).