0% found this document useful (0 votes)
43 views19 pages

Namespaces Handout

Namespaces were introduced in C++ to solve the problem of name clashes between global variables and functions when using multiple libraries or source files. Namespaces allow related identifiers to be grouped together and referenced unambiguously, avoiding conflicts. Key features of namespaces include: 1. Grouping related identifiers under a namespace avoids naming collisions between different libraries/source files. 2. Unnamed or anonymous namespaces make variables and functions private to the current source file, similar to static. 3. Using declarations and directives control visibility of namespaces across files. 4. Standard library identifiers like iostream are contained within the std namespace.

Uploaded by

Jeremy Pho
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
43 views19 pages

Namespaces Handout

Namespaces were introduced in C++ to solve the problem of name clashes between global variables and functions when using multiple libraries or source files. Namespaces allow related identifiers to be grouped together and referenced unambiguously, avoiding conflicts. Key features of namespaces include: 1. Grouping related identifiers under a namespace avoids naming collisions between different libraries/source files. 2. Unnamed or anonymous namespaces make variables and functions private to the current source file, similar to static. 3. Using declarations and directives control visibility of namespaces across files. 4. Standard library identifiers like iostream are contained within the std namespace.

Uploaded by

Jeremy Pho
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 19

Introduction to Namespaces [Prasanna Ghali]

Namespaces
"The road to hell is paved with global variables" - Steve McConnell

The purpose of this handout is give you an introductory, "big picture" presentation on
namespaces. After reading this document, you should be able to:

1. Understand the purpose of namespaces in C++. In other words, what problem from C was
solved by inventing them?
2. Have knowledge of when namespaces aren't very useful.
3. Understand advantages of unnamed or anonymous namespaces.
4. Explain using declarations and using directives.
5. Know the meaning of different types of headers such as <iostream.h> , <iostream> ,
<string> , <string.h> , and <cstring> in the C++ standard library namespace std .

It is important to understand the concept of namespaces because they show up everywhere.


Although namespaces are not a sub-topic of generic programming, they become important in the
presence of function templates. For example, making sense of a topic called argument-dependent
lookup relies on a good understanding of namespaces.

References
1. Section of the required text C++ Primer explains namespaces.
2. Microsoft provides a short introduction to namespaces while this page provides coverage
related to syntax.

What is a variable? What is an object?


Let's begin by understanding what a variable is and what an object is. A variable is an object that
has a name. An object, in turn, is a part of the computer's memory that has a type. This distinction
is important because it is possible to have objects that don't have names. This happens when
intermediate objects are created when expressions are evaluated or when objects have dynamic
storage duration. An example with built-in and user-defined types:

1 int add(int lhs, int rhs) {


2  return lhs + rhs;
3 }
4
5 std::string add(std::string lhs, std::string rhs) {
6  return lhs + rhs;
7 }
8
9 int main() {
10  std::cout << add(int {2}, int {5}) << "\n";
11  std::cout << add(std::string{"Hello"}, std::string{"World"}) << "\n";
12 }

In this example, the arguments in the first call to function add are evaluated to unnamed objects
of type int which are then used to initialize parameters lhs and rhs of function add . The
expression lhs+rhs further evaluates to an unnamed object of type int which is returned by
value. Thus, the call to function add will evaluate to an unnamed object of type int . The only
variables encountered in this code are the two parameters of function add .

1 / 19
Introduction to Namespaces [Prasanna Ghali]

The second call to function add is also evaluated in the same manner except that std::strig is
the type of objects and variables.

Scope and linkage


The scope or visibility of a variable is the region of program text over which the name is visible and
can be referenced by other entities. Variables defined outside a function are called external
variables and the scope of an external variable lasts from the point at which it is declared in the
file to the end of the file being compiled. External variables are said to have global scope, and
sometimes also referred to as file scope.

Linkage describes the accessibility of a variable between different source files or even within the
same source file. There are three types of linkage: no linkage, external linkage, and internal linkage.

All variables declared inside a function including its arguments are internal or private to the
function and can only be accessed from inside the function. Since these variables can never be
accessed from other functions, we say that internal variables of a function have no linkage.

All external variables have the default property that all references to them by the same name,
from any source file - even from a source file different than the one in which the external variable
is defined - are references to the same thing. This property is called external linkage. External
linkage implies that a program consisting of many source files must have one and only one
definition of an external variable in these source files. However, there could be as many compatible
declarations as required of the external variable. In C++, this rule is called the One Definition Rule
(or, ODR).

The ability of allowing an external variable in a source file be accessible to other functions in the
same source file but inaccessible to functions in other source files is called internal linkage. The
author of a source file can ensure internal linkage for an external variable by adding keyword
static to the declaration specifier.

Problems with global scope


The biggest issue with the global scope is that there's only one of them. In small programs, this is
not a problem, since one programmer may produce all of these names. When programming in the
large, there is usually a bevy of people putting names in this singular scope, and invariably this
leads to name conflicts. For example, library1.h sourced from one library vendor might define
a number of constants, including the following:

1 double const LIB_VERSION = 1.204;

Ditto for library2.h that is sourced from a different library vendor:

1 int const LIB_VERSION = 3;

It doesn't take great insight to see that there is going to be a problem if one of your source file
tries to include both library1.h and library2.h . Unfortunately, outside of cursing under your
breath, sending hate mail to the library authors, and editing the header files until the name
conflicts are eliminated (which may not be possible with libraries since you don't have access to
source files), there is little you can do about this kind of problem.

A similar situation would arise with variable and function names declared at global scope in
different source files of the same program. Consider the following source file mine.cpp that
defines four names in global scope:

2 / 19
Introduction to Namespaces [Prasanna Ghali]

1 #include <iostream>   // std::cout


2
3 int counter {1};     // counter in global scope
4 int strength {2};     // strength in global scope
5
6 int Div2(int value) { // Div2 in global scope
7  return value / 2;
8 }
9
10 int main() { // main in global scope
11  std::cout << counter << "\n";  // use global counter
12  std::cout << strength << "\n"; // use global strength
13  std::cout << Div2(8) << "\n";  // use global Div2
14 }

Consider another source file yours.cpp that also defines a global variable named strength :

1 double strength {22.33};         // strength in global scope


2
3 double incr_strength(double x) { // incr_strength in global scope
4  return x + strength;
5 }
6
7 // other stuff here ...

Both source files independently compile without flagging any errors. However, in the process of
creating an executable program, the linker will flag an error:

1 /usr/bin/ld: yours.o:(.data+0x0): multiple definition of `strength'; mine.o:


(.data+0x0): first defined here
2 collect2: error: ld returned 1 exit status

The particular issue faced by the linker is that it is unable to reconcile the multiple definitions of
external variable strength - one definition in mine.cpp and the second definition in yours.cpp .
Recall the ODR rule requires a program have one and only one definition of an external variable.

Programmers try to reduce the possibility of name clashes by prepending some hopefully-unique
prefix to each of their global names. Rather than risk having multiple definitions of name
strength in the global scope, the author of mine.cpp might name the external variable as
hlpr1_strength while another author might name their external variable as hlpr2_strength .
Surely you must admit that the resulting names are less than pleasing to use and hard to
understand.

It is possible that certain external variables only require internal linkage rather than external
linkage. Programmers can reduce the possibility of name clashes by making external variables in
source files have internal linkage by adding keyword static to the declaration statements of
these variables. After amending yours.cpp so that external variable strength has internal
linkage, it is now possible to satisfy the ODR rule and remove the previous linker error.

3 / 19
Introduction to Namespaces [Prasanna Ghali]

1 // revised version of yours.cpp


2 static double strength {22.33}; // make name strength private to this file
3
4 double incr_strength(double x) {
5  return x + strength;
6 }

Namespaces
To avoid name clashes in the global scope, we have seen two C-style options:

Prepend some hopefully-unique prefix to each global name


Make certain global names private to the source file by adding keyword static to the
declaration specifier of the variable. Such an external variable will now have internal linkage.

The first option makes names less than pleasing to use and hard to understand while providing
the required external linkage for the variables and functions defined with these names. The
second option enforces internal linkage of variables and function to a certain source file
preventing their use by other source files. Is there a better solution that avoids name clashes for
global variables in a program while allowing both uncluttered names and external linkage? C++
namespaces avoid name clashes and yet provide programmers the best of both worlds: define
global variables having both external linkage and uncluttered, pleasing, and easy to understand
names.

Namespace definitions
At its core, a namespace is just a fancy way of introducing a new scope that lets you use the
simplest and most easy-to-understand names without confusing other programmers. Further,
namespaces can be used to control whether a name has internal or external linkage. The general
form of a namespace definition is:

1 namespace user-defined-name { // user-defined-name introduces a new scope


2  declaration/definition
3  declaration/definition
4 ...
5 }

A namespace can only be defined at the global scope or within another namespace. This
means you can't define local namespaces inside functions nor struct s nor class es).
user-defined-name must be unique in the global namespace. If user-defined-name is the
name of a previously defined namespace, then you're adding declarations or definitions to
the pre-existing namespace. This also means that namespaces can be discontiguous.
Any declaration or definition that can appear in the global scope can appear in a user-
defined namespace. This includes class es, struct s, declaration and definitions of
functions and variables, templates, and other namespaces (nested).

Accessing names in namespaces


Suppose, the code in mine.cpp handles the implementation of mathematical types and functions
for a software project. The names in the global scope can then be put in a unique namespace
called helpers :

4 / 19
Introduction to Namespaces [Prasanna Ghali]

1 namespace helpers { // namespace helpers creates new scope


2  
3 int counter {1};
4 int strength {2};
5 int Div2(int value) {
6  return value / 2;
7 }
8  
9 } // like code blocks, namespaces don't end with a semicolon!!!

However, placing these names in a namespace will prevent mine.cpp from compiling:

1 namespace helpers { // namespace helpers creates new scope


2  
3 int counter {1};
4 int strength {2};
5 int Div2(int value) {
6  return value / 2;
7 }
8  
9 } // like code blocks, namespaces don't end with a semicolon!!!
10
11 int main() { // main in global scope
12  std::cout << counter << "\n";  // error!!! name counter is not declared
13  std::cout << strength << "\n"; // error!!! name strength is not declared
14  std::cout << Div2(8) << "\n";  // error!!! name Div2 is not declared
15 }

Clients can access names in namespace helpers in any of three ways: by importing all names in
a namespace into a scope; by importing individual names into a scope; or by explicitly qualifying a
name for one-time use.

Here is an example of importing all names in namespace into a scope:

1 int main() { // main in global scope


2  using namespace helpers; // make all names in helpers available without
3                           // qualification in this scope
4  std::cout << counter << "\n";
5  std::cout << strength << "\n";
6  std::cout << Div2(8) << "\n";
7 }

Here is an example of importing individual names in namespace into a scope. Since namespace
helpers introduces a unique scope, we need to qualify the names in the namespace:

1 int main() { // main in global scope


2  using helpers::counter;        // make only name counter available without
3  std::cout << counter << "\n";  // qualification in this scope
4  using helpers::strength;       // make only name strength available without
5  std::cout << strength << "\n"; // qualification in this scope
6  using helpers::Div2;           // make only name Div2 available without
7  std::cout << Div2(8) << "\n";  // qualification in this scope
8 }

5 / 19
Introduction to Namespaces [Prasanna Ghali]

Here is an example of explicitly qualifying a name for one-time use. The name Div2 is visible only
in scope helpers and to reference the name in global scope, the name must be qualified with
the namespace:

1 int main() { // main in global scope


2  std::cout << helpers::counter << "\n";  // for one-time use
3  std::cout << helpers::strength << "\n"; // ditto
4  std::cout << helpers::Div2(8) << "\n";  // ditto
5 }

Namespace definitions don't have to be contiguous


Namespace definitions do not have to be contiguous:

1 namespace helpers {
2 int counter {1};
3 int strength {2};
4 }
5
6 // other code here ...
7
8 namespace helpers {
9 int Div2(int value) {
10 return value / 2;
11 }
12 }

However, all namespace members must be declared before their first use:

1 namespace helpers {
2 int counter {1};
3 int strength {2};
4 }
5
6 int main() { // main in global scope
7  std::cout << helpers::counter << "\n";  // ok: helpers::counter declared
8  std::cout << helpers::strength << "\n"; // ok: helpers::strength declared
9  std::cout << helpers::Div2(8) << "\n";  // error: math::Div2 not declared
10 }
11
12 namespace helpers {
13 int Div2(int value) { // definition
14 return value / 2;
15 }
16 }

Line will not compile since math::Div2 is declared after its first use.

Interfaces and implementations


We declare names in one namespace definition and define them in another. This is now OK in
mine.cpp :

1 namespace helpers {

6 / 19
Introduction to Namespaces [Prasanna Ghali]

2 extern int counter;  // declaration


3 extern int strength; // ditto
4 int Div2(int);       // ditto
5 }
6
7 int main() { // main in global scope
8  std::cout << helpers::counter << "\n";  
9  std::cout << helpers::strength << "\n";
10  std::cout << helpers::Div2(8) << "\n";  // Ok, compiles and links
11 }
12
13 namespace helpers {
14 int counter {1}; // definition
15 int strength {2}; // ditto
16 int Div2(int value) { // definition
17 return value / 2;
18 }
19 }

Note also that the separate definitions of the same namespace (as above) can be in separate files
as well. They don't have to be in the same physical source file (and often they won't be). This gives
you the flexibility to put the interface for your code into the public files (header files) where your
users can see it, and keep the implementation hidden in source files.

A header file helpers.h containing the interface looks like this:

1 namespace helpers {
2 extern int counter;  // need declaration not definition
3 extern int strength; // ditto
4 int Div2(int);       // ditto
5 }

The implementation would look like this in source file helpers.cpp :

1 namespace helpers {
2 int counter {1}; // definition
3 int strength {2}; // ditto
4
5 int Div2(int value) { // ditto
6 return value / 2;
7 }
8 }

You can now use the interface in mine.cpp like this:

1 #include <iostream>
2 #include "helpers.h"
3
4 int main() { // main in global scope
5  std::cout << helpers::counter << "\n";  // ok, compiles
6  std::cout << helpers::strength << "\n"; // ditto
7  std::cout << helpers::Div2(8) << "\n";  // ditto
8 }

7 / 19
Introduction to Namespaces [Prasanna Ghali]

Accessing same name from more than one namespace


Now lets turn our attention to yours.cpp . Recall the author of yours.cpp used keyword static
to make external variable strength have internal linkage:

1 // revised version of yours.cpp


2 static double strength {22.33}; // make name strength private to this file
3
4 double incr_strength(double x) {
5  return x + strength;
6 }

What happens if the author deletes the keyword static and makes external variable strength
have external linkage? The program consisting of source files mine.cpp , helpers.cpp , and
yours.cpp will compile and link because names strength and helpers::strength exist in
global scope and namespace scope helpers , respectively. That is, a new scope helpers has
been carved out of the global scope. To avoid future name clashes (as more source files are
added to the project), the external name strength in yours.cpp is declared in a unique
namespace, say phys :

1 namespace phys { // namespace phys creates new scope


2  
3 double strength {22.33}; // make name strength private to this file
4 double incr_strength(double x) {
5  return x + strength;
6 }
7  
8 }

Using the idea of interfaces and implementations, let's provide the declarations for names in
namespace phys in header file yours.h :

1 namespace phys { // namespace phys creates new scope


2  
3 extern double strength;       // need declaration not definition
4 double incr_strength(double); // ditto
5 }

and provide the definitions in source file yours.cpp :

1 #include "yours.h"
2
3 namespace phys {
4 double strength {22.33};         // definition
5 double incr_strength(double x) { // ditto
6  return x + strength;
7 }
8 }

One of the nicest things about namespaces is that you can use the strength variables defined in
namespaces helpers and phys without conflict, provided you explicitly say which namespace's
strength you wanted:

8 / 19
Introduction to Namespaces [Prasanna Ghali]

1 // mine.cpp
2 #include <iostream>
3 #include "helpers.h"
4 #include "yours.h"
5
6 int main() { // main in global scope
7  std::cout << helpers::counter << "\n";  // ok
8  std::cout << strength << "\n";          // error!!! which strength?
9  std::cout << helpers::strength << "\n"; // fine, no ambiguity
10  std::cout << phys::strength << "\n";    // also no ambiguity
11  std::cout << helpers::Div2(8) << "\n";  // ok
12 }

Scope resolution operator ::


Consider the following code fragment:

1 #include <iostream>
2
3 int main() {
4  std::cout << "Hello World!!!\n";
5 }

The name std::cout on line is a qualified name, which uses the scope resolution operator :: .
To the left of the :: is the (possibly qualified) name of a scope which in the case of std::cout is
the namespace std . To the right of the :: is a name that is defined in the scope named on the
left. Thus, std::cout means the "name cout that is in the namespace scope std ."

As shown in the following code fragment, the :: operator allows you to access hidden global
variables:

1 #include <iostream> // std::cout


2
3 int foo {1}; // foo in global scope
4 int bar {2}; // ditto
5
6 void func() {
7  int foo {10};    // local foo #1 hides global foo
8  int bar {foo};   // local bar #1 hides global bar
9  int baz {::foo}; // local baz #1 initialized with global foo
10
11  if (bar == 10) {  // local bar #1
12    int foo {100};  // local foo #2 hides local #1 and global
13    bar = foo;      // local bar #1 is set to local foo #2
14    foo = ::bar;    // local foo #2 is set to global bar
15 }
16
17 ::foo = foo;   // global foo assigned value of local foo #1
18 ::bar = ::foo; // global bar assigned value of global foo
19
20  std::cout << "foo is " << foo << "\n";     // local foo #1 is 10
21  std::cout << "bar is " << bar << "\n";     // local bar #1 is 100
22  std::cout << "::foo is " << ::foo << "\n"; // global foo is 10
23  std::cout << "::bar is " << ::bar << "\n"; // global bar is 10
24 }

9 / 19
Introduction to Namespaces [Prasanna Ghali]

The definition of variable foo in line hides global variable foo ; that is, any references to name
foo in the scope of function func are to the nearest valid declaration of name foo (which is the
declaration on line ). In C, if a global variable is hidden by a new declaration with the same name,
there is no way to access the global variable. In C++, the :: operator makes it possible to access
a hidden global variable. If the left of the :: is empty then the right is a name that is defined in
the global scope of the program. Thus the initializing expression on line ::foo means the
"name foo that is in the program's global scope."

The definition of foo on line hides variable foo declared on line (which in turn hides global
variable foo declared on line ). Any references to name foo in the if statement block are to
the foo declared on line . Again, you can access the global variable foo using expression
::foo . However, there is no way to access the hidden variable on line . This means that if you
hide a name in an outer scope, you can never refer to it unless the hidden name was global. That
is, there is no way to access any hidden names in any intermediate scope.

Nested namespaces
Eventually, as your programs get larger and larger, even a namespace is going to have hundreds
or thousands of names. Having everything in a single namespace may lead to conflicts. Names
associated with specific portion of the program (such as graphics library or numerical library or
I/O library) can be put into related namespaces. Just like we partitioned the global scope using
namespaces, we can partition a namespace's scope by nesting these related namespaces within
the outer namespace to create a hierarchy of namespaces. This idea of nested namespaces is
somewhat similar to nested structures. Here is an example:

1 #include <iostream> // std::cout


2
3 namespace DigiPen {
4  int Div2(int x) {return x / 2;}
5  
6  namespace IntroProg {
7    int Div2(int x) {return x / 2;}
8 }
9
10  namespace AdvProg {
11    int Div2(int x) {return x >> 1;}
12 }
13 }
14
15 int main() {
16  std::cout << DigiPen::Div2(8) << "\n";
17  std::cout << DigiPen::IntroProg::Div2(8) << "\n";
18  std::cout << DigiPen::AdvProg::Div2(8) << "\n";
19 }

Unnamed namespaces
What happens when we run out of unique names for namespaces? It's unlikely to happen, but as
more and more code uses namespaces, the chances for a collision are high. Namespace names
are global, so there's no way to protect them from other global names. This is a problem if code
uses lots of small namespaces. We could come up with some kind of globally unique ID scheme to
guarantee unique namespaces:

10 / 19
Introduction to Namespaces [Prasanna Ghali]

1 namespace NS_1E266980_A661_48B6_94D1_C9DEA80A328B {
2  // stuff
3 }
4
5 namespace NS_6FB60AE7_AEEE_4285_88A7_6F0C28B34B5B {
6  // other stuff
7 }

This option makes names that are cluttered, less than pleasing to use, and hard to understand. A
better approach is unnamed namespaces:

1 #include <iostream> // std::cout


2 #include <cmath>    // std::sqrt
3
4 namespace {
5  double my_sqrt(double x) { return std::sqrt(x); }
6 }
7
8 int main() {
9  std::cout << my_sqrt(25.0) << "\n";   // no qualification needed
10  std::cout << ::my_sqrt(25.0) << "\n"; // my_sqrt in global scope
11 }

The my_sqrt function is defined in an unnamed namespace. As shown on line , no qualification


is required to refer to function my_sqrt . Likewise, as shown on line , the scope operator ::
can also be used to refer to function my_sqrt .

If we have a name in an unnamed namespace that is the same as a global name in our program,
we won't be able to access the name in the unnamed namespace.

1 #include <iostream> // std::cout


2 #include <cmath>    // std::sqrt
3
4 namespace {
5  double my_sqrt(double x) { return std::sqrt(x); }
6 }
7
8 double my_sqrt(double x) { return std::sqrt(x); } // global
9
10 int main() {
11  // error: is it from unnamed namespace or line 8?
12  std::cout << my_sqrt(25.0) << "\n";
13  // calling global function on line 8
14  std::cout << ::my_sqrt(25.0) << "\n"; // ok
15 }

Names in an unnamed namespace are local to the file in which the unnamed namespace is
defined. By having similar names in anonymous namespaces in different source files, we can keep
these names private to each source file. This is similar to using keyword static to provide
internal linkage to global variables and functions in a source file.

Design tip: To provide internal linkage to external variables and functions, prefer to use
unnamed namespaces over the already-overused keyword static .

11 / 19
Introduction to Namespaces [Prasanna Ghali]

Namespace aliases
Given these namespaces:

1 namespace AdvancedProgramming {
2  int foo {11};
3  int bar {12};
4  int f1(int x) { return x / 2; }
5 }
6
7 namespace IntroductoryProgramming {
8  int foo {21};
9  int bar {22};
10  int Div2(int x) {return x / 2; }
11 }

using them requires a lot of typing:

1 int main() {
2  std::cout << AdvancedProgramming::foo << "\n";
3  std::cout << IntroductoryProgramming::Div2(8) << "\n";
4 }

To allow unique namespaces and to shorten the names, you can create a namespace alias:

1 // declare these after the namespace definitions above


2 namespace AP = AdvancedProgramming;
3 namespace IP = IntroductoryProgramming;
4
5 int main() {
6  // now, use the shorter aliases
7  std::cout << AP::foo << "\n";
8  std::cout << IP::foo << "\n";
9  std::cout << AP::f1(8) << "\n";
10  std::cout << IP::Div2(8) << "\n";
11 }
12
13 void func() {
14  // you can "re-alias" a namespace (must be in different scope)
15  namespace AP = IntroductoryProgramming;
16
17  std::cout << AP::f1(8) << "\n";   // now, an error no f1 in AP
18  std::cout << AP::Div2(8) << "\n"; // ok
19  std::cout << IP::Div2(8) << "\n"; // same as above
20 }

Aliases defined outside of a function are still only visible within the file they were defined (i.e.
they are not global).
You can "re-alias" a namespace later in the code, as shown on line . However, the
redefinition must happen in a new scope. Otherwise, it is an illegal redefinition.
Once you create an alias, you can't "un-create" it. You can only re-alias it.

Programming tip: Overuse of namespace aliases may also lead to confusion.

12 / 19
Introduction to Namespaces [Prasanna Ghali]

Programming tip: Be careful when you redefine an alias as it may just lead to more
confusion.

Aliases for nested namespaces


Creating aliases for nested namespaces as well:

1 namespace AdvancedProgramming {
2  int Div2(int x) {return x >> 1;}
3 }
4
5 namespace AP = AdvancedProgramming; // alias for global namespace
6
7 namespace DigiPenInstituteOfTechnology {
8  int Div2(int x) { return x / 2; }
9  
10  namespace IntroductoryProgramming {
11    int Div2(int x) { return x / 2; }
12 }
13
14  namespace AdvancedProgramming {
15    int Div2(int x) { return x >> 1; }
16 }
17 }
18
19 namespace DIT    = DigiPenInstituteOfTechnology;
20 namespace DIT_IP = DigiPenInstituteOfTechnology::IntroductoryProgramming;
21 namespace DIT_AP = DIT::AdvancedProgramming;  // uses previous alias
22
23 // possible to have multiple aliases
24 namespace CS120 = DIT::IntroductoryProgramming;
25 namespace CS225 = DIT::AdvancedProgramming;
26
27 int main() {
28  // these are all equivalent
29  std::cout <<
30    DigiPenInstituteOfTechnology::IntroductoryProgramming::Div2(8) << "\n";
31  std::cout << DIT::IntroductoryProgramming::Div2(8) << "\n";
32  std::cout << DIT_IP::Div2(8) << "\n";
33  std::cout << CS120::Div2(8) << "\n";
34
35  // these are equivalent
36  std::cout << DIT_AP::Div2(8) << "\n";
37  std::cout << CS225::Div2(8) << "\n";
38 }

Note that you can't do this:

1 std::cout << DIT::AP::Div2(8) << "\n";

because AP is not a member of DIT namespace. That is, the alias on line cannot be used like a
preprocessor #define`.

Another example:

1 namespace DigiPenInstituteOfTechnology {

13 / 19
Introduction to Namespaces [Prasanna Ghali]

2  namespace GAM400 {
3    namespace Graphics {
4      void initialize();
5      // other stuff here
6   }
7
8    namespace Physics {
9      void initialize();
10      // other stuff here
11   }
12
13    namespace Network {
14      void initialize();
15      // other stuff here
16   }
17 }
18 }

Now, with one alias like this:

1 namespace DIT = DigiPenInstituteOfTechnology;

You can access symbols inside the hierarchy something like this:

1 DIT::GAM400::Graphics::initialize();
2 DIT::GAM400::Physics::initialize();
3 DIT::GAM400::Network::initialize();

Design tip: Don't create very terse namespaces like std . Create unique and meaningful
namespaces and let the user create shorthand notation with aliases.

using declarations
Like any other declaration, an using declaration introduces names declared in a namespace
scope in the current scope. It allows you to make specific names declared in a namespace
accessible without requiring the namespace and scope resolution operator. Example:

1 namespace Stuff {
2  int foo {11}; // Stuff::foo
3  int bar {12}; // Stuff::bar
4  int baz {13}; // Stuff::baz
5 }
6
7 namespace Stuff2 {
8  int bar {111}; // Stuff2::bar
9 }
10
11 // name foo accessible in rest of file scope without namespace qualifier
12 using Stuff::foo;
13
14 void f1() {
15  Stuff::foo = 21;   // ok: using namespace
16  foo = 22;          // ok: namespace not required
17  using Stuff::bar;  // make bar available in this scope only
18  bar = 30;          // ok

14 / 19
Introduction to Namespaces [Prasanna Ghali]

19  int bar {5};       // error: redeclaring name bar declared in line 17


20  using Stuff2::bar; // error: redeclaring name bar declared in line 17
21 }
22
23 void f2() {
24  int foo {3};    // This is a new foo, it hides Stuff::foo
25  Stuff::foo = 4; // ok, using qualified name
26 ::foo = 5;      // ok, global foo (i.e. Stuff::foo)
27 }
28
29 int foo {222}; // error: redeclaring name foo declared in line 12
30
31 int main() {
32  foo = 23;         // ok because of using declaration on line 12
33  bar = 30;         // error: name bar not declared in this scope
34  using Stuff::baz; // make baz available in this function only
35  baz = 40;         // ok
36 }

Some salient points about the above code:

using declarations declare a name, which means you can't redeclare/redefine with the same
name in the same scope, as shown below on lines , , and .
If many functions in the file need access to a name in a namespace, you should probably put
the using declaration at the top of the file, outside of any function, as is done on line .
An using declaration placed outside of a function has file scope not global scope.
If only a few functions need the name, you should put the using declaration in the
function(s) where the name is needed, as is done on lines and 4.

using directives
An using directive allows you to make all names in a namespace visible at once. Assume we have
these names in a namespace:

1 namespace Stuff {
2  int foo {11};  // Stuff::foo
3  int bar {12};  // Stuff::bar
4  int baz {13};  // Stuff::baz
5 }

We can make them all accessible with a using directive:

1 // every name in Stuff is visible from here down in the file


2 using namespace Stuff;
3
4 int main() {
5  std::cout << foo << "\n";  // Stuff::foo
6  std::cout << bar << "\n";  // Stuff::bar
7  std::cout << baz << "\n";  // Stuff::baz
8 }

using directives are scoped; they apply only within the block where the directive is specified:

15 / 19
Introduction to Namespaces [Prasanna Ghali]

1 int main() {
2  // every name in Stuff is visible only in this scoe
3  using namespace Stuff;
4  
5  std::cout << foo << "\n";  // Stuff::foo
6  std::cout << bar << "\n";  // Stuff::bar
7  std::cout << baz << "\n";  // Stuff::baz
8 }
9
10 // unqualified members in Stuff not available here.

Ambiguity errors are detected when an ambiguous name is referenced, not when the directive is
encountered:

1 namespace Stuff2 {
2  int bar {111}; // Stuff2::bar
3 }
4
5 using namespace Stuff;  // make all names from Stuff accessible
6 using namespace Stuff2; // make all names from Stuff2 accessible
7
8 foo = 10; // ok, Stuff::foo
9 bar = 30; // error: which bar? this is ambiguous.

Of course, qualified names can override the using directive.

1 Stuff::bar = 100;  // OK


2 Stuff2::bar = 200; // OK

More detailed example:

1 namespace Stuff {
2  int foo {11};       // Stuff::foo
3  int bar {12};       // Stuff::bar
4  int baz {13};       // Stuff::baz
5 }
6
7 void f1() {
8  int foo {3};        // local, hides nothing
9  int x {Stuff::foo}; // ok
10  int y {bar};        // error, bar is unknown
11 }
12
13 int foo {20};         // global ::foo
14
15 int main() {
16  using namespace Stuff; // Stuff's members accessible without
17                         // qualifier Stuff:: in this function
18  std::cout << ::foo << "\n";      // no problem, global
19  std::cout << Stuff::foo << "\n"; // no problem, Stuff::foo
20  std::cout << foo << "\n";        // ambiguity error: ::foo or Stuff::foo?
21
22  std::cout << bar << "\n";  // Stuff::bar
23  std::cout << baz << "\n";  // Stuff::baz
24

16 / 19
Introduction to Namespaces [Prasanna Ghali]

25  int foo {3};        // ok: hides Stuff::foo and ::foo


26  int x {Stuff::foo}; // ok: use qualified name
27  x = foo;            // ok: local foo above
28  x = ::foo;          // ok: global foo
29 }

Summarizing the above code:

using directives are not meant to be used to make it "easier" on the programmer (by saving
keystrokes).
Many using directives will cause global namespace to be polluted, which is the primary
purpose of namespaces to begin with.
It's best to avoid using directives because they've the potential of polluting a scope by
inserting all the names from the namespace.

Programming tip: Neve use using directives in header files that are meant to be used by
others. Aren't all header files for others to use?

std namespace
C++'s standard library is incredibly big: out of the pages in the specification, the base
language only takes about pages while the library takes about pages. Because the
library is big, it contains a lot of functionality. The other important detail about the library is that
almost everything in it is a template. Because the library has so much in it, there's a reasonable
chance you may choose a class or function name that's the same as a name in the standard
library. To shield you from the name conflicts that would result, virtually everything in the
standard library since C++98 (the first C++ ISO standard was formalized in 1998) is nestled in
namespace std . But that lead to a new problem. Before C++98, gazillions of lines of C++ code
were written with a pseudo-standard library that relied on functionality declared in headers
<iostream.h> , <complex.h> , <limits.h> , <stdlib.h> , etc. That pseudo-standard library
wasn't designed to use namespaces nor templates. To allow existing code to continue to compile
with C++98 compilers, the C++98 standard decided to retain the pseudo-standard library for a
period of time and create new headers for the std -wrapped components. The algorithm for
creating new headers was trivial: the .h on existing C++ headers was simply dropped. So
<iostream.h> became <iostream> in C++98 and future standards. For C headers, the same
algorithm was applied, but a c prepended to each result. Hence C's <string.h> became
<cstring> , <stdio.h> became <cstdio.h> . The old C++ headers were officially deprecated
while the C headers are being maintained for compatibility with ISO C but are expected to be
deprecated in future versions.

Practically speaking, this is the C++ header situation:

Old C++ header names like <iostream.h> were officially deprecated in C++98 and therefore
were removed from the official standard. The contents of such headers are not in
namespace std . Compiler vendors supported these non-standard headers for many years
to keep alive pre-1998 code. Currently, most mainstream compilers do not support pre-
C++98 style headers.
C++98 header names like <iostream> contain the same basic functionality as the
corresponding old headers, but the contents of the headers are in namespace std .
Standard C headers like <stdio.h> continue to be supported [but as mentioned earlier
these headers are expected to be deprecated in future versions]. The contents of such
headers are not in std .

17 / 19
Introduction to Namespaces [Prasanna Ghali]

New C++ headers for functionality in the C library have names like <cstdio> . They offer the
same contents as the corresponding old C headers, but the contents are in std .

All this seems a little weird at first, but it's really not that hard to get used to. The biggest
challenge is keeping all the string headers straight: <string.h> is the old C header for char* -
based string manipulation functions, <string> is the std -wrapped C++ header for C++ string
classes, and <cstring> is the std -wrapped version of the old C header. If you can master that
(and I know you can), the rest of the library is easy.

Now that we've seen some of the details of how namespaces are created and used, let's look at
how they can be applied with std namespace. This code should be easy to understand now:

1 #include <iostream>  // for std::cout and std::endl


2 using namespace std; // for access to *all* names inside std namespace
3
4 int main() {
5  cout << "Hello" << endl;
6 }

The using directive in the above code is not recommended, but typically seen in high-school C++
courses and throughout the web. A better way is to use using declarations to control which
names in namespace std to bring into the program:

1 #include <iostream> // for std::cout and std::endl


2 using std::cout;    // using declaration, global scope
3 using std::endl;    // using declaration, global scope
4
5 int main() {
6  cout << "Hello" << endl;  // std::cout and std::endl
7 }

Rather than polluting the file scope with names cout and endl , an even better way to write the
above using declarations is to limit their scope to function main :

1 #include <iostream> // for std::cout and std::endl


2
3 int main() {
4  using std::cout;  // using declaration, local scope
5  using std::endl;  // using declaration, local scope
6  
7  cout << "Hello" << endl;  // std::cout and std::endl
8 }

I believe the preferred way is to limit polluting even the function scope and instead to write code
that uses the C++ standard library using qualified names:

1 #include <iostream>  // for std::cout and std::endl


2
3 int main() {
4  std::cout << "Hello" << std::endl;
5 }

Now we can write code like this (to ensure job security):

18 / 19
Introduction to Namespaces [Prasanna Ghali]

1 #include <iostream> // for std::cout and std::endl


2
3 int main() {
4  int cout {16};    // cout is an int
5  cout = cout << 3; // multiply cout by 8
6  std::cout << cout << 5 << std::endl;   // std::cout is a stream, prints:
163
7  std::cout << (cout << 5) << std::endl; // std::cout is a stream, prints:
128
8 }

Of course, we would never write code like the above! But, there are thousands of names in the
C++ global namespace, so the chances that you collide with one is pretty good. You should learn
to take control over when, where, and how names are introduced into your programs. Don't
introduce names "accidentally." C++ gives the programmer complete control, but this power is
often abused (or not fully understood) by beginning C++ programmers. Namespaces were added
to help simplify management of large programs. If you're writing a trivial, throw-away program,
it's probably not a big deal if you have using directives outside of your functions.

Here's a classic example of the problem with a using directive:

1 #include <algorithm> // STL algorithms


2 using namespace std; // make the whole C++ universe available!
3
4 int count = 0;
5
6 int increment() {
7  return ++count; // error, identifier count is ambiguous
8 }

The using directive in line will introduce name count declared in namespace std to file
scope. In that same scope, the programmer is defining variable count . Thus, the reference to
name count in line is ambiguous. Hopefully, that should convince you that using directives
should be used judiciously.

19 / 19

You might also like