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.
References :- https://docs.microsoft.com/en-us/cpp/cpp/namespaces-cpp
Comments
Post a Comment
If you have any doubt, please let me know.