Namespaces


Namespaces are ways of collecting symbols (function names, class names, etc.) into logical groups. This helps avoid naming conflicts that occur when large numbers of people work on the same project. It also helps organize the pieces of code that logically go together as a unit.

Namespaces are a powerful concept that we probably shouldn't be talking about now, but unfortunately, we have to. They affect how we use everything from the standard C++ libraries.

Whenever we need to use anything from a namespace we need to declare it as coming from that particular namespace. (An example follows.)

Everything in the standard C++ libraries belongs to the the namespace std.

(The standard C libraries are unaffected. This is by design.)

It used to be that we could write the following program:

#include <iostream>
#include <iomanip>

int main()
{
    double num1;
    double num2;
    
    cout << "Enter first floating-point number: ";
    cin >> num1;
        
    cout << "Enter second floating-point number: ";
    cin >> num2;
            
    cout << "The sum of the numbers is " << fixed << setprecision(2)
         << num1 + num2 << endl;
                
    return 0;
}

This will not compile. cin, cout, endl, fixed, and setprecision belong to the standard namespace and that must be specified. There are three ways that we can do so.

Option #1: Qualified names

To specify that an object belongs to a namespace, give the namespace name, a double colon, and then the name of the object used.

Doing that turns the program code into the following:

#include <iostream>
#include <iomanip>

int main()
{
    double num1;
    double num2;

    std::cout << "Enter first floating-point number: ";
    std::cin >> num1;

    std::cout << "Enter second floating-point number: ";
    std::cin >> num2;

    std::cout << "The sum of the numbers is " << std::fixed << std::setprecision(2)
              << num1 + num2 << std::endl;

    return 0;
}

Code in header (.h) files should use qualified names to specify the namespace to which items belong. Using this option in implementation (.cpp) files can get ugly very quickly, especially when you start doing some formatting. Fortunately, there is a solution: the keyword using.

Option #2: Code individual using declarations

With a using declaration, we can declare what symbols we are going to be using from a given namespace. The declarations are placed at the beginning of the file, before any of the symbols they reference are used.

#include <iostream>
#include <iomanip>
        
using std::cin;
using std::cout;
using std::endl;
using std::fixed;
using std::setprecision;

int main()
{
    double num1;
    double num2;

    cout << "Enter first floating-point number: ";
    cin >> num1;

    cout << "Enter second floating-point number: ";
    cin >> num2;

    cout << "The sum of the numbers is " << fixed << setprecision(2)
         << num1 + num2 << endl;

    return 0;
}

If a lot of different things are being used from a namespace, there could be a lot of using declarations at the beginning of a file. This is okay.

Option #3: Code a using directive

The using directive declares the use of the entire namespace, rather than declaring each symbol.

#include <iostream>
#include <iomanip>

using namespace std;
    
int main()
{
    double num1;
    double num2;

    cout << "Enter first floating-point number: ";
    cin >> num1;

    cout << "Enter second floating-point number: ";
    cin >> num2;

    cout << "The sum of the numbers is " << fixed << setprecision(2)
         << num1 + num2 << endl;

    return 0;
}

This last usage is very common, especially in older textbooks, and is often taught in introductory-level courses. It is generally considered bad programming style. It essentially throws away the protective powers of a given namespace. The use of using declarations in implementation (.cpp) files is highly encouraged.

Here is a list of some of the most commonly used items in CSCI 241 that belong to namespace std:

cin cout cerr endl
fixed scientific setprecision setw
left right internal setfill
showpos string npos vector
istream ostream ifstream ofstream