Namespaces in C++
In C++, all identifiers in the global scope must be unique. This may become a problem, especially in larger projects where a programmer uses a lot of components from different libraries. In such cases there's high chance that two components will have the same name in two different libraries, a situation called name collision or conflict. This makes impossible to use those libraries together.
In C and some other languages this problem is solved by adding a specific prefix to the names of all identifiers in a specific library. This guarantees that there are no equal identifiers in any two libraries. Unfortunately this increases the length of the identifiers and thus reduces readability and convenience of programming.
Namespaces are an elegant solution to the problem. Instead of an immutable prefix to the identifier names, namespaces introduce a new, named scope. From within the namespace, all identifiers are referenced as usual. However, if one wants to refer to the identifiers from outside the namespace, the namespace prefix nmname:: must be prepended, where nmname is the name of the namespace. See the example below:
This section is incomplete Reason: standard std namespace |
#include <iostream> namespace yyy { void baz() { std::cout << "baz\n"; } void foo() { baz(); } // no need to append the name of the namespace } // namespace yyy namespace zzz { void foo() { std::cout << "foo\n"; } } // namespace zzz int main() { yyy::foo(); // Both functions can be called, even though zzz::foo(); // they have the same name }
Output:
baz foo
Note that the // namespace yyy comments are not required, they are only there only for clarity.
Contents |
Syntax
This section is incomplete Reason: Explain a bit more precisely |
Nested namespaces
This section is incomplete Reason: Name lookup is more complex cases, etc |
Importing a namespace
One of the features of a namespace is that it's possible to remove the namespace prefix to save a bit of typing. The basic syntax of a namespace import declaration is as follows:
using namespace nmspace_name;
After such declaration, all names that we would otherwise have referred as nmspace_name::identifier can be used simply as identifier.
#include <iostream> namespace yyy { namespace zzz { void baz() { std::cout << "baz"; } } // namespace zzz using namespace zzz; void foo() { baz(); // Can use baz without zzz:: zzz::baz(); // Still can use baz explicitly } } // namespace yyy using namespace yyy; int main() { yyy::foo(); // explicit cal foo(); // yyy was imported // The following four call the same function via different path yyy::zzz::baz(); // Explicit call, this would be needed if we didn't // import the namespaces zzz::baz(); // The contents of namespace yyy were imported into the global namespace yyy::baz(); // The contents of namespace zzz were imported into the yyy namespace baz(); // baz was imported into yyy and then into the global namespace std::cout << "\n"; }
Output:
bazbazbazbazbazbaz
This section is incomplete Reason: Do not do using namespace std |
Alias
The verbosity of namespaces can be an advantage as well as an inconvenience. Consider the following example:
#include <boost/asio.hpp> int main() { boost::asio::io_service io; boost::asio::ip::tcp::socket s(io_service); return (0); }
As you can see, this is getting a little too verbose and can lead to confusion. You could use "using", but you will loose all verbosity.
This is where aliases come in handy:
#include <boost/asio.hpp> namespace boost_tcp = boost::asio::ip::tcp; int main { boost::asio::io_service io; boost_tcp::socket s(io_service); return (0); }
By making a alias, you can clear out your code while still keeping some verbosity.
Conclusion
Namespaces are not essential in order to make a functioning program, but it is a good practice and should be considered when writing at least a meduim-sized program, especially if it contains modules or APIs.