The Global Namespace
Let's dive right in by taking a look at an example.
Sample: GlobalNamespaceSample\GlobalNamespaceSample.cpp
#include <iostream> #include <ostream> #include "../pchar.h" int g_x = 10; int AddTwoNumbers(int a, int b) { return a + b; } int _pmain(int /*argc*/, _pchar* /*argv*/[]) { int y = 20; std::wcout << L"The result of AddTwoNumbers(g_x, y) where g_x = " << g_x << L" and y = " << y << L" is " << AddTwoNumbers(g_x, y) << L"." << std::endl; if (true == 1) { std::wcout << L"true == 1!" << std::endl; } return 0; }
In the previous sample, we define two functions, AddTwoNumbers
and wmain
. These two functions are both in the global namespace. The global namespace is the base level in which everything else within the program exists. C++, owing to its C heritage, allows you to define anything within the global namespace (so you can define namespaces, classes, structures, variables, functions, enums, and templates).
C# also has the concept of a global namespace, but it does not allow you to define anything within it other than namespaces and types. In the previous example, we have the statement int g_x = 10; which defines an integer named g_x within the global namespace and assigns it a value of 10. This is what is commonly referred to as a global variable. In C# global variables are illegal.
As a brief aside, every programming language I have ever worked with has had its share of bad features—things the language allows, but things that usually lead to issues. These issues include hard-to-debug problems, subtle errors that go unnoticed for a long time, maintainability problems, readability problems, and all the other frustrating things that add many hours to development time without any benefit. C++ is no different. When we come across something that fits this description, I will do my best to call it out. This is one of those times.
Global variables are bad. Avoid them whenever possible. There is a common convention when using them in C++, which is to prefix the variable name with g_, as in the previous example. While this helps to alert you and other programmers to the fact that this is a global variable, it does not change the fact that it is a global variable, having all the problems I described. This isn’t a book on bad programming practices, so I’m not going to spend time explaining why global variables are bad. All you need to know is this feature exists in C++, but you should avoid using it whenever possible.
The Scope Resolution Operator ::
In C++, ::
is the scope resolution operator. It is used for separating nested namespaces, for separating types from their namespace, and for separating member functions and variables from their type.
Note that it is only used in the last situation when performing the following:
- Defining a member function.
- Accessing a member of a base class within a member function definition.
- Accessing a static member function or variable.
- Assigning a value to a static member variable.
- Fetching the address of a member function.
In other instances, you use either the . operator or the -> operator, depending on whether you are accessing the member directly or via a pointer.
This can seem complicated since C# just uses the . operator for all of the purposes that ::, ., and -> are used for in C++.
Note: We'll discuss the . and -> operators later. For now, you just need to know that they are used for accessing instance member variables and non-static member functions (which you use depending on whether or not you are working with a pointer).
For the most part, you'll be fine. The only place you’re likely to trip up is if you try to access a base class member by using the . operator rather than the :: operator, or if you try to specify an enum member using something other than ::. If you ever compile your program and receive a syntax error complaining about "missing ';' before '.' ", it's a good bet you used a . where you should've used a :: instead.
Defining Namespaces
A namespace is defined in much the same way as it is in C#. Here is an example:
Sample: NamespacesSample\NamespacesSample.cpp
#include <iostream> #include <ostream> #include <string> #include "../pchar.h" using namespace std; namespace Places { namespace Cities { struct City { City(const wchar_t* name) { Name = wstring(name); } wstring Name; }; } } int _pmain(int /*argc*/, _pchar* /*argv*/[]) { auto nyc = Places::Cities::City(L"New York City"); wcout << L"City name is " << nyc.Name.c_str() << L"." << endl; return 0; }
Note: Never include a using directive in a header file. If you do that, you don’t just import the types and namespaces in that namespace into the header file, you also import them into any source or header file that includes the header file. This causes really nasty namespace pollution issues. We’ll be discussing header files next, so anything that’s unclear about this should make sense then. Just remember that having a using namespace directive in a header file is a bad idea; only use them in your source code files.
Conclusion
As in most languages, namespaces are important in C++ to keep everything organized and to avoid name collisions. In the next installment of this series, we'll focus on functions and classes.
This lesson represents a chapter from C++ Succinctly, a free eBook from the team at Syncfusion.
Comments