About namespaces.
In C there sometimes (especially in large projects) occurred a problem named name conflicts. This means that you have more than one function or global variable with the same name, in different modules (probably written by different programmers). Like here:
Code:
/* module1.c */
void PrintDebugData(void)
{
/* blablabla printf blablabla */
}
/* module2.c */
void PrintDebugData(void)
{
/* blablablu puts bluble printf bla */
}
Those functions perform similar but different tasks: both output runtime information of the data in this module.
The code will compile fine, but the linker will discover the two functions with same names and will not know which one to use when there's a reference to PrintDebugData somewhere.
In practice the only solution was often renaming the function and searching for every call to this function and changing it to the new name.
C++ has introduced the concept of namespaces to battle this problem. A namespace is a named area of variable visibility. You can for example do:
Code:
namespace A
{
int i;
};
namespace B
{
int i;
};
and the two names will not conflict. Now the programmers with conflicting names could just wrap their whole files in two differently named namespaces and be fine.
The most important operator that is to be remembered is the :: (scope resolution) operator. It is used to make clear which namespace you mean. e.g. A::i means the i defined in namespace A, B::i means the i defined in namespace B. ::i would mean the i defined outside any namespace (the "global scope"), if there was one.
This requires a few things to remember:
Code:
int i;
namespace A
{
int i;
void func()
{
i = 4; // means A::i, because we are inside A
B::i = 3; // means B::i
::i = 2; // means the global i
}
};
namespace B
{
int i;
void func()
{
i = 4; // means B::i, because we are inside B
A::i = 3; // means A::i
::i = 1; // means the global i
}
};
void main()
{
i = 5; // means the global i
A::i = 2; // means A::i
B::i = 1; // means B::i
A::func(); // calls A::func, afterwards ::i = 2, A::i = 4, B::i = 3
B::func(); // calls B::func, afterwards ::i = 1, A::i = 3, B::i = 4
func(); // ERROR: no function named func in global scope
}
The code above won't compile, firstly because of the call to undefined ::func, but also because B::i is referenced before it gets defined. Which leads us to the next section:
Continuing namespaces.
When you define a struct or class, once you close the braces it's done. You can't later reopen them and add something:
Code:
struct S
{
int a, b;
};
// we now want to extend the struct:
struct S
{
int c, d;
};
This code will result in an error: struct S is already defined.
Namespaces allow this. You can do
Code:
namespace NS
{
int a, b, c;
void func();
};
// do something
namespace NS
{
double d, e, f;
double func2(int i);
};
// NS now contains a, b, c, d, e, f, func and func2
So, in order to make the above code compile you'd do this:
Code:
int i;
namespace B
{
int i;
};
namespace A
{
int i;
void func()
{
i = 4; // means A::i, because we are inside A
B::i = 3; // means B::i, now works because B::i is declared above
::i = 2; // means the global i
}
};
namespace B // extending B
{
void func()
{
i = 4; // means B::i, because we are inside B
A::i = 3; // means A::i
::i = 1; // means the global i
}
};
void main()
{
i = 5; // means the global i
A::i = 2; // means A::i
B::i = 1; // means B::i
A::func(); // calls A::func, afterwards ::i = 2, A::i = 4, B::i = 3
B::func(); // calls B::func, afterwards ::i = 1, A::i = 3, B::i = 4
}
You may also nest namespaces:
Code:
namespace A
{
int i;
namespace B
{
int i;
};
};
A::i = 4;
A::B::i = 456;
Now A, B or NS aren't very good names for namespaces: they might easily get into conflict again, thus removing all the benefit they ever had. You'd better choose namespace names like PROGRAMMERNAME_MODULENAME_GLOBALS. Which has other problems:
Code:
namespace SebastianRedl_AiPathFinding_Globals
{
void FindPath(POSITION from, POSITION to);
int g_iIterations;
};
// set number of iterations:
SebastianRedl_AiPathFinding_Globals::g_iIterations = 100;
// call:
SebastianRedl_AiPathFinding_Globals::FindPath(mouseClickPos, unit.location);
// My fingers are falling off!
This is why there is the using keyword. There are two ways to use it: per-element or whoel namespaces.
Code:
namespace SebastianRedl_AiPathFinding_Globals
{
void FindPath(POSITION from, POSITION to);
int g_iIterations;
};
namespace SebastianRedl_AiPatrollingEnemy_Globals
{
POSITION NextPatrolMark(UNIT unit);
double g_dAggresivity;
};
// because we have many calls to NextPatrolMark
// we don't want to type the namespace identifier every time.
// This is where using comes into play:
using SebastianRedl_AiPatrollingEnemy_Globals::NextPatrolMark;
// Now we can call the function like this:
POSITION posTo = NextPatrolMark(units[4]);
// both g_iIterations and FindPath from the other
// namespace are often called, import the whole namespace at once:
using namespace SebastianRedl_AiPathFinding_Globals;
g_iIterations = 80;
FindPath(units[4].location, posTo);
You can also create alias names for namespaces:
Code:
namespace SomeNameSpace
{
int i;
};
namespace XYZ = SomeNameSpace;
XYZ::i = 4; // sets SomeNameSpace::i
All new C++ headers (those without the .h) define all their elements within the namespace std. Because you often don't know in advance which elements you use (or because you use so many) you don't import the elements selectively with the using std:: syntax but rather grab the whole namespace with a simple
using namespace std;