Namespaces in C++

Namespaces in C++


A namespace provides a scope in which its members (variables, functions, classes etc.) are declared/defined. C++ has many libraries and their might be a situation where one identifier(name of the variables, functions, classes etc.) in one library is same as another identifier in another library. Hence to avoid the name conflicts, we use namespaces.

Defining Namespaces

Lets take a basic example of a namespace.

 1 
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#pragma once
using namespace std;
// Name of the namespace is demo
namespace demo {

	// defining a function named greet
	void greet() {
		cout << "Hello" << endl;
	}

	// defining a function named farewell
	void farewell() {
		cout << "Good Bye" << endl;
	}
}

Above is the header file in which we have defined a namespace named demo.

Namespace declaration starts with the keyword namespace and then the namespace name, in this case demo. In this namespace, we have defined two functions, first is greet(), which says "Hello", and second is farewell(), which says "Good Bye". 

Suppose we hadn't defined the function in the namespace and their is another function named greet() in the huge C++ library (collection of code which make up the language), there would have been a name conflict, therefore we defined this function in namespace demo.

There are 3 ways through which we can access the members of a namespace

1. Using the fully qualified name

 1 
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#include<iostream>
// including the header file which has the namespace
#include "namespaces.h"

using namespace std;

int main() {
	// using a qualified name to access the members of the namespace
	demo::greet();
	demo::farewell();
	return 0;
}

In the above example, we use the qualified name to access the member function of the demo  namespace, on line 9 and 10.

demo::greet();
demo::farewell();

A fully qualified name is when we write the namespace name followed by the scope operator (::) followed by the name of the member you want to access. This way we have qualified access to the members of the namespace.

2. Using the "using" declaration to bring an individual identifier into scope.

 1 
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include<iostream>
// including the header file which has the namespace
#include "namespaces.h"

using namespace std;

int main() {
	// using the "using" declaration to bring
	// individual members into scope
	using demo::greet;
	using demo::farewell;

	greet();
	farewell();
	return 0;
}

In the above example on line 10 and 11,


using demo::greet;
using demo::farewell;

We brought both the member functions into scope individually, using the "using" declaration. This way is useful when we need one or two members of a namespace.

3. Using the "using" directive.

 1 
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#include<iostream>
// including the header file which has the namespace
#include "namespaces.h"

using namespace std;
// using the "using" directive
using namespace demo;
int main() {

	greet();
	farewell();
	return 0;
}

In the above example, we used the "using" directive on line 7, which will bring all the members of the namespace into scope. This should be used when we use many of the namespace members.

We can define a namespace in multiple blocks in the same file and within multiple files, for example

 1 
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// namespace_header.h
#pragma once

namespace demo {		// defining first block of namespace demo
	void greet() {
		std::cout << "Hello" << std::endl;
	}
}
/*
* 
* some code
* 
*/
namespace demo {		// definition continues in the second block
	void farewell() {
		std::cout << "Good Bye" << std::endl;
	}
}

In the above example the namespace demo is divided in two blocks and likewise it's parts can be defined in multiple files. Same is with namespace std, it is defined in many blocks in many header files in the C++ library.

Members declared in the namespaces can be defined outside the namespace through explicit qualification. But the definition of the member should come after the point of their declaration in the namespace.

 1 
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#pragma once
using namespace std;
namespace demo {
    
    void greet();
}

// defining the declared function
void demo::greet() { cout << "Hello" << endl; } 
// error: farewell() is not a member of demo yet
void demo::farewell() { cout << "Goodbye" << endl; }

namespace demo {
    void farewell(); // declaring the member function
}

In the above example, function greet(), which is declared in the first block of namespace demo, is defined outside the namespace definition through explicit qualification. And on line 11, the function farewell() is defined through explicit qualification but the problem is at that point the function farewell() is not the part of the namespace demo, it is declared in the namespace demo, in its second block on line 14. So that becomes an error. The declaration and definition should be the correct order.

Global namespaces

An identifier which is not declared or defined in an any namespace, it is the part of the global namespace. Global namespace identifiers can be qualified by appending only the scope operator and no namespace name.

 1 
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include<iostream>
using namespace std;

int int1 = 1;	// variable defined in global namespace

int main() {
	// local variable in the main function
	int int1 = 2;
	
	// using the scope operator to access the global identifier
	::int1 = 2;

	return 0;
}

In the above example, on line 4, a global variable int1 is defined. Also in the main function, a variable named int1 is defined. Because the names are same, the global variable int1 is hidden in the main function, to use the global variable int1, we need to qualify the  name  being used that is, appending the scope operator (::) to the member name, there is no need of a namespace name. On line 11 we used a fully qualified name to access the global variable int1.

Let's look at Nested Namespaces

Nested namespace is a namespaces under a namespace. The code under parent namespace do not has unqualified access to child namespace's members, but the code in the child namespace has unqualified access (no need to append the namespace name and the scope operator to the members to be accessed) to the members of the parent namespace.

Below is an example.

 1 
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#pragma once
// parent namespace
namespace parent {
	void func1() {			// function defined in parent namespace
		std::cout << "Welcome to the parent namespace THROUGH THE CHILD NAMESPACE."<< std::endl;
	}
	// child namespace
	namespace child {
		// function defined in the child namespace
		void func2() {
			// returns the result of a call to the function in the parent namespace
			return func1();	
		}
		void func3() {		// Another function in the child namespace
			std::cout << "This is the child namespace THROUGH THE PARENT NAMESPACE." << std::endl;
		}
	}
	void func4() {		// another function in the parent namespace
		// have to use the scope operator to access the child namespace members
		return child::func3();
	}
}

Namespace definition starts from line 3, that is the parent namespace, in which we defined function func1. From line 8, a namespace named child is defined.

In the child namespace a function named func2 is defined, which returns the result of the call to the function func1, which is defined in the parent namespace. Here the code in the child namespace has unqualified access to the members of the parent namespace.

From line 14, function func3 is defined, on line 17 child namespace definition completes. Now we are in the parent namespace, on line 18 function named func4 is defined which returns the result of the call to the function func3, which is defined in the child namespace. Here we have to use the qualified name to access the members of the child namespace.

There is a case when the members of the child namespace can be accessed without using the qualified name, that is when the child namespace is defined as inline.

Inline Namespaces

Following is the example of an inline nested namespace. The below example is same as the above example except on line 8, the child 

 1 
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#pragma once
// parent namespace
namespace parent {
	void func1() {			// function defined in parent namespace
		std::cout << "Welcome to the parent namespace THROUGH THE CHILD NAMESPACE."<< std::endl;
	}
	// child namespace defined as inline
	 inline namespace child {
		// function defined in the child namespace
		void func2() {
			// returns the result of a call to the function in the parent namespace
			return func1();	
		}
		void func3() {		// Another function in the child namespace
			std::cout << "This is the child namespace THROUGH THE PARENT NAMESPACE." << std::endl;
		}
	}
	void func4() {		// another function in the parent namespace
		// we don't have to use the scope operator to access the child namespace members
		return func3();
	}
}

namespace is defined as inline, and on line 20, the namespace name and the scope operator is gone, as the child namespace is defined as inline, the code in the parent namespace has unqualified access to the members of the child namespace.

Declaring and defining namespace members

One thing to keep in mind while "declaring" members in a namespace is when you define that very member at a different place you need to provide a fully qualified name even if you use the "using" directive.

Below is an example.

1 
2
3
4
5
#pragma once
namespace demo {
	// just declaring the function greet
	void greet();
}

In above code, we have just declared a function in a namespace in a header file.

 1 
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include<iostream>
#include "namespace_header.h"

using namespace std;
// using directive to use the namespace demo
using namespace demo;

// To define the function we need a qualified name
void demo::greet() {
	cout << "Hello" << endl;
}

int main() {
	greet();
	return 0;
}

In the above example, on line 6 we using the "using" directive to bring into scope every thing in the namespace demo, despite that we have to use the qualified name to define the function greet() which was declared in namespace demo. If we didn't do this, the function greet(), will be an individual function having global scope and the compiler is confused between two overloaded functions (functions with same name), the first one is declared in the namespace and the second is the defined in the global namespace in the cpp file which is an error.

Namespace Aliases

 1 
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include<iostream>
using namespace std;

// namespace with a very big name
namespace this_is_the_namespace_name {
	void greet() {
		cout << "Hello" << endl;
	}
}

// alias for the big name
namespace NSName = this_is_the_namespace_name;

int main() {
	NSName::greet();
	return 0;
}

In the above example, namespace this_is_the_namespace_name is defined, as it is a very big name, on line 12 we made an alias for the namespace name.


namespace NSName = this_is_the_namespace_name;

Now instead of this_is_the_namespace_name we can write NSName. On line 15 we used the alias name to access the greet function.

Anonymous / unnamed namespaces

A namespace without a name is called anonymous or unnamed namespace. The anonymous namespace or its members are not visible to the code outside the file in which it is defined.

 1 
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include<iostream>
using namespace std;

// namespace with no name
namespace  {
	void greet() {
		cout << "Hello" << endl;
	}
}

int main() {
	greet();
	return 0;
}

In the above example, on line 5, their is no name for the namespace and also we don't need the qualified access to the members.

Comments