9.12. Namespaces And The Scope Resolution Operator

Time: 00:05:10 | Download: Large, Large (CC), Small | Streaming, Streaming (CC) | Slides (PDF)

In one form or another, we have used namespaces throughout the textbook in all the example programs and the programming assignments you have completed. Chapter 1 introduced the standard namespace, std, and illustrated two options for accessing the I/O system with it. This brief section will demonstrate how to create and, more generally, use namespaces.

"A namespace is a declarative region that provides a scope to the identifiers (the names of types, functions, variables, etc) inside it. Namespaces are used to organize code into logical groups and to prevent name collisions that can occur especially when your code base includes multiple libraries" (Microsoft Documentation). To understand how namespaces work and why we need them, we must understand what a "name collision" means.

Linguists estimate that there are more than a million words in English, and there are likely similar numbers in other languages. So, it seems like we should be able to write a program without running out of identifier names. For example, using English's 26-character alphabet, we can form nearly 457,000 four-character patterns, almost half the number of words in the language. But most of those patterns are meaningless. Furthermore, programmers often name programming elements based on their role in a program (i.e., on what they do). This practice sets the stage for potential name collisions.

It's easy to resolve name collisions by changing one of the colliding names when a programming team works together to create a system. But when we create a system incorporating multi-sourced components delivered as executables and object-code libraries (Figure 4, step 3), it's not possible to change conflicting names. I encountered this problem while integrating a database management system with library code licensed by different vendors. Namespaces solves this problem by creating named scopes.

Vendors avoid name collisions by declaring functions and variables in uniquely named namespaces with names typically based on corporate names, which are trademarked and, therefore, unique. Namespaces included in the C++ API are managed and reserved by the ANSI C++ committee. C++ binds the namespace name to the names of its functions and variables with the scope resolution operator. The name "scope resolution operator" suggests that it helps the compiler determine the scope of otherwise ambiguous programming elements.

namespace Acme
{
    void print(string name);
};

namespace Widgets_galore
{
    void print(string part);
};
void Acme::print(string name)
{
    cout << "Acme " << name << endl;
};

void Widgets_galore::print(string part)
{
    cout << "Widgets_galore " << part << endl;
}
(a)(b)
int main()
{
    Acme::print("Dilbert");
    Widgets_galore::print("wing nut");
    return 0;
}
// Error - a namespace is an invalid data type

Acme m;
Widgets_galore* wg = new Widgets_galore;

 
(c)(d)
Namespaces and the scope resolution operator. The simplified code demonstrates the "namespace" keyword and how to create, fill, and use namespace structures. The scope resolution operator (displayed with red characters) has two operands. The left-hand operand is a namespace name, and the right-hand operand is the name of a feature declared in it. The operator binds the feature to the namespace's scope.
  1. Namespaces are syntactically similar to classes and structures; like them, they create a new, named scope.
  2. The namespace is included with and attached to the function definition with the scope resolution operator. Although not illustrated here, we can include small function bodies in the namespace.
  3. When client code calls a namespace function, it must use the namespace name and the scope resolution operator to form the complete function name.
  4. However, unlike classes and structures, programmers cannot create variables or objects from a namespace.
class beta
{
    public:
        string to_string(int value)
            { return std::to_string(value); }
};
namespace std
{
	string to_string(int value);
};

 
(a)(b)
Clarifying ambiguous scope with the scope resolution operator. Programs may contain non-conflicting, overloaded functions (functions with the same name), but proper overloading requires that they have unique parameter lists. In some cases, it's desirable to have non-overloaded functions with the same name and parameters.
  1. Class beta defines a to_string member function that calls the C++ string class to_string function (see string To Number and Number To string). Without the namespace name and the scope resolution operator, the call becomes a direct recursion function call. Programmers use the scope resolution operator to resolve the ambiguous use of function names as illustrated here by to_string.
  2. C++ declares the common or standard C++ library functions in the std namespace, and programs can usually access them without ambiguity just by adding the "using" statement at the beginning of a file.