Using And Creating Namespaces in C++
Have you ever wondered what using namespace std means? In this tutorial, you will learn that and how to create your own namespaces.
74
3
Namespaces In C++
When you start learning C++, you were probably told to add the line using namespace std; in your code, but you were never told why. Or, maybe you were not taught this way, but instead, you had to do things such as std::cout << "Hello world!" << std::endl;. What was that all about?
Using Namespace Std
Let's look at the following C++ code segments and compare them:
code1.cpp
#include <iostream> using namespace std; int main() { cout << "Hello world!" << endl; return 0; }
code2.cpp
#include <iostream> int main() { std::cout << "Hello world!" << std::endl; return 0; }
In code1.cpp, we are using the famous statement using namespace std;. In code2.cpp, we are not, but when calling cout, we call it by prepending the namespace std: std::cout. Why is that? To answer that question, first, let's try and run this code segment:
code3.cpp
#include <iostream> int main() { cout << "Hello world!" << endl; return 0; }
As you can see, this segment does not have using namespace std;, and we are not prepending cout with std::. So, did it run? You can try this C++ online compiler. If you tried it, you probably got this error; error: ‘cout’ was not declared in this scope. So, what does that mean? In order to understand that, we must know what is a namespace.
What Is A Namespace?
A namespace is simply a scope–other than the global scope–in which you add your code, that is, where you define your constants, variables, functions, objects, etc. If you don't know what a scope is, have a look here. From this point forward, I will assume that you know what a scope is. When you are calling a function, method, variable, constant, if it is not a local or global function, you must specify the scope to which it belongs, and that is, specify the namespace in which it is defined. The main purpose of namespaces is the keep code clean and organized and prevent name collisions. A lot of big companies out there want to develop their own code and not use standard ones, so they use their own namespaces and place their code there.
The C++ standard functions, cout, endl, cin, etc. are all defined in the std namespace (or scope), therefore, you must specify to which scope they belong, or simply add the statement using namespace std;. By using that statement, you are telling the compiler that if the function is not defined in the local or global scope, try to find it in the std scope. That means, that if you have a function defined in the global scope with the same name as a function defined in a namespace, the global function will be prioritized, unless you explicitly say to look for it a namespace, such as (std::function). Let's look at the following example:
#include <iostream> using namespace std; int max(int x, int y) { cout << "Calling my max function." << endl; return x > y ? x : y; } int main() { int m = max(5, 6); cout << m << endl; return 0; }
You should see Calling my max function. printed as the function max is called. In case you were not aware, there is a function max defined in the C++ standard library. If we now ran this code:
#include <iostream> using namespace std; int max(int x, int y) { cout << "Calling my max function." << endl; return x > y ? x : y; } int main() { int m = std::max(5, 6); cout << m << endl; return 0; }
You should only see a 6 printed because the max function was called from the std namespace instead of the global scope. If we are in the reversed scenario and we want to ensure that the function gets called from the global scope and not from any namespace, we call it in this way:
#include <iostream> using namespace std; int max(int x, int y) { cout << "Calling my max function." << endl; return x > y ? x : y; } int main() { int m = ::max(5, 6); cout << m << endl; return 0; }
As you can see, you now have :: with no namespace specified. That means that the compiler will look only in the global scope.
The Scope Resolution Operator
Are you wondering what :: means? Well, that is the scope resolution operator, and its job is to tell the C++ compiler in which scope to find you variable, constant, or function. If you are familiar with objects in C++, then you might have seen something like this:
#include <iostream> class MyObj { public: void setX(int y); int getX(); private: int x; }; void MyObj::setX(int y) { x = y; } int MyObj::getX() { return x; }
As you can see, we are using the scope resolution operation to tell the compiler that the setX and getX functions are defined in the scope of the object MyObj. If we did not do that, we would get an error because a variable x is not defined within the function scope or in the global scope, rather, in the scope of MyObj. If we created a new function newFunc, and we were not making a reference to any variable defined in the scope of MyObj, we would not get any errors, but the function would be defined in the global scope, so if we did this: MyObj obj; obj.newFunc(), we would get an error because it is not defined in the scope of MyObj.
In general, the compiler always follows this chain when looking for a variable, constant, or function with no namespace specified:
- Look in the local scope (always looking in the most local scope) and moving up to outer local scopes
- Look in the global scope
- Look in namespaces (when you have the using namespace statement).
Let's look at the following example:
#include <iostream> using namespace std; const int x = 4; int main() { int x = 6; cout << "1: " << x << endl; if (x > 5) { int x = 11; cout << "2: " << x << endl; if (x > 10) cout << "3: " << ::x << endl; } return 0; }
If you ran this code, you would see printed:
1: 6
2: 11
3: 4
In the first output, it is looking for the variable in its scope, and that scope happens to be where we declare and initialize x to 6. In the first if statement, we are checking whether the local x (6) is greater than 5, and it is true, therefore its body is executed. In that body, we declare yet another variable x and initialize it to 11. In the second output, we see 11 being displayed because it is the variable in its nearest scope. In the second if statement, we check if x is greater than 10, and the x in its nearest scope is 11, therefore it is true. In its body is the third output, but here we use the scope resolution operator to tell the compiler to look in the global scope, so 4 is printed.
Now that we know how scopes work, how about we create our own namespaces?
Creating New Namespaces
Now that you know what namespace are and how to use them, let's build a namespace for this new library I am coding. This library is all about geo-positioning, therefore, I want to call it geo. I want to keep all of my prototypes in a header file, and my definitions in a C++ file. My testing will be in a separate C++ file. So let's begin:
geo.h
#ifndef GEO_H #define GEO_H namespace geo { struct Position { double lat; double lon; }; void enableGeo(); void disableGeo(); bool isGeoEnabled(); Position &getCurrentPos(); // Get current position of user } #endif /* GEO_H */
geo.cpp
#include "geo.h" // static makes it private static bool enabled = false; static geo::Position *pos = nullptr; // current position if enabled, otherwise nullptr void geo::enableGeo() { if (!enabled) { pos = new Position; // Get current position code here... enabled = true; } } void geo::disableGeo() { if (enabled) { delete pos; pos = nullptr; enabled = false; } } bool geo::isGeoEnabled() { return enabled; } geo::Position &geo::getCurrentPos() { assert(!enabled); // Return error if enabled is not true Position pos = *::pos; // Notice no geo:: is needed to access Position return pos; // Returning local pos (a copy) }
testing.cpp
#include <iostream> #include "geo.h" int main() { geo::Position pos; geo::enableGeo(); if (geo::isGeoEnabled()) pos = geo::getCurrentPos(); std::cout << "Latitude: " << pos.lat << "Longitud: " << pos.lon << std::endl; return 0; }
As you can see in the file geo.h, defining a new namespace is very trivial. It is just like defining a new block starting with the keyword namespace, followed by the desired name, and in curly brackets, defining your variables, constants, and functions. In the file geo.cpp, you may have noticed that implementing a function, is identical to implementing an object function. Notice how in the function geo::getCurrentPos we are referring to *::pos to refer to the private global pointer variable pos, and not the local one. Also, note how the return type is geo::Position, but inside of the function, we refer to it as simply Position. The reason is that we are telling the compiler that the function itself is in the geo namespace, therefore, we needn't specify it inside of the function body.
We could have also used the statement using namespace geo; in both geo.cpp and testing.cpp, and that would eliminate the need of using geo::.
Extending Existing Namespaces
If you wish to extend an already existing namespace, you simply define it as if it was a new definition of it:
std_extension.h
#ifndef STD_EXTENSION_H #define STD_EXTENSION_H namespace std { int myMax(int x, int y); } #endif /* STD_EXTENSION_H */
std_extension.cpp
#include "std_extension.h" int std::myMax(int x, int y) { return x > y ? x : y; }
testing.cpp
#include <iostream> #include "std_extension.h" int main() { std::cout << std::myMax(5, 6) << std::endl; return 0; }
As you can see, extending an existing namespace is as simple defining it as if it was a new one.
Nested Namespaces
Nesting namespace is as easy as nesting objects, loops, or other statements:
nesting.h
#ifndef NESTING_H #define NESTING_H namespace std { namespace mystd { int myMax(int x, int y); } } #endif /* NESTING_H */
nesting.cpp
#include "nesting.h" int std::mystd::myMax(int x, int y) { return x > y ? x : y; }
testing.cpp
#include <iostream> #include "nesting.h" int main() { std::cout << std::mystd::myMax(5, 6) << std::endl; return 0; }
Try It Yourself
Can you develop the header and C++ file for a new namespace space with the following:
- An object Galaxy that has properties name (string), and number of solar systems (int). It must have methods to get and set these properties.
- A function getCurrentGalaxy, that returns the Milky Way Galaxy object (it has 1 solar system).
Thank You
Thank you for reading this tutorial. Don't forget to leave your comments below and share if you enjoyed!
74
3