C++: Namespaces
In C++, namespaces are simply named scopes of code, most commonly used to prevent naming conflicts. A lot of the standard library C++ stuff is declared in the 'std' namespace as we've previously discussed, and as such most of our applications up until this point have contained the line using namespace std;
near the top of the document. This line brings the namespace into the scope where the using
statement is written, and as such we usually bring everything from the 'std' namespace into a global scope so that we don't have to manually scope out each instance of cout
, endl
, or other things that use the std
namespace using the scope resolution operator - e.g. std::cout
and std::endl
.
The problem is that putting a using namespace
statement at the top of our different code documents somewhat defeats the point of namespaces. Everything was put inside the 'std' namespace to prevent naming conflicts with other things, but we're just telling everything to come back out into the global scope so we can use them. This isn't a brilliant idea, as can be demonstrated by something like the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
The above will not compile as the compiler simply doesn't know whether to use the "string" declared in the 'std' namespace in the "string" header file which we brought into a global scope by using namespace std;
, or to use the "string" structure that we declared. Just to go off on a small tangent, if you're interested in making this example somewhat more practical and testing your knowledge of dynamic memory allocation, it might be a good idea to actually try to create your own "string" class by dynamically allocating character arrays. An example solution is as follows (it's a little messy, but it works!), it might be a good idea to read through it to see how much you can understand (we've covered it all):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
|
The problem with having to use the namespace name and scope resolution operator before things that "live" in a certain namespace is that typing things like std::cout
a bunch of times can get tiring and repetitive - even if we don't want everything from the 'std' namespace brought into a more accessible scope, it's usually safe to say that we want 'cout' to relate to the 'std' namespace. As such we can use the using
keyword to specifically use the 'std' namespace for certain cases by typing something like using std::cout;
. This is generally better accepted than something like using namespace std;
as we're specifically selecting components of the 'std' namespace which we want to bring into scope. The good thing about this method is that it explicitly specifies the parts of the namespace which we want to use in the specified scope, and as such this is often considered one of the best methods for utilizing functionality from namespaces. The following would resolve the original naming conflict which we encountered in this safe and explicit manor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
In the above, an even better solution (depending on how the rest of the program is planned out) might be to put our two explicit using
statements into the main function. This means that instead of std::cout
and std::endl
being brought into the global scope, they will be brought into the scope of main - avoiding any possible naming conflicts with our functions, classes, and other things. Similarly, the whole using namespace std;
line could be moved into main
if appropriate, but often this is not a good solution.
You can, of course, create namespaces of your own! This is simply done by using the namespace
keyword, followed by the name of the namespace, followed by what you want the namespace to contain, in curly brackets. Namespaces can contain pretty much anything you want them to, the important part is using them to group similar things, or things with generic names. An example of some custom-made namespaces is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Although the above is a rather abstract example, it should demonstrate the concept of and process of creating namespaces. We can also create aliases (other names) to namespaces if we need to - this can be done by using the equals operator on a new namespace, so something like namespace alias_name = std;
would provide an alternative name to 'std' with no problems:
1 2 3 4 5 6 7 8 9 10 11 |
|
Namespace aliasing can become particularly useful when you have nested namespaces. Take, for example, the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|