The
name of a thing matters. Along with its
type, a thing is uniquely identifiable. In all programming languages, C++ included, you cannot name and type two things identically. Were you able to do that, the language would become non-deterministic.
Imagine having identical twin children, and naming them "Alice". How would you distinguish them? You could not, unless you were to do something to make them different. (Alice with dyed-red hair. Or Alice Ann and Alice Lynnette.)
A related concept, which I think you are confusing here, is called
function overloading, where you give two things of
different types the same name.
1 2
|
void doit( unsigned x ); // overload 1: takes an integer argument
void doit( std::string s ); // overload 2: takes a string argument
| |
The compiler can tell which of these you mean by simply looking at the
type of argument you give it:
1 2
|
doit( 17 ); // that there is an integer -- you must want overload 1
doit( "42" ); // that there is a string -- you must want overload 2
| |
Another related concept is
namespaces. Namespaces were created to avoid name collisions among library implementors.
Suppose company X and company Y both implement nice compression algorithm. They are different algorithms, but both companies want, naturally, to name their compression functions "compress" and "decompress".
Now suppose that you want to write a little program that can manipulate compressed files using either method. You #include the headers for each companies libraries, compile, and ... the compiler and/or linker complains that you have two different things with the same name and type.
In order to overcome this problem, companies X and Y are both smart enough to wrap their functions in namespaces.
1 2 3 4 5 6 7 8 9 10 11 12
|
// company X's awesome compression routines
//
namespace company_x
{
template <typename InputIterator, typename OutputIterator>
OutputIterator
compress(
InputIterator first,
InputIterator last,
OutputIterator result
);
}
| |
1 2 3 4 5 6 7 8 9 10 11 12
|
// company Y's excellent compression routines
//
namespace company_y
{
template <typename InputIterator, typename OutputIterator>
OutputIterator
compress(
InputIterator first,
InputIterator last,
OutputIterator result
);
}
| |
Now, as you can imagine, you can choose which compression library to use because the routines both have
different fully-qualified names. Alice Ann and Alice Lynnette at work:
1 2 3 4
|
if (user_wants_compression_x)
company_x::compress( source.begin(), source.end(), ostream_iterator <char> ( myfile ) );
else
company_y::compress( source.begin(), source.end(), ostream_iterator <char> ( myfile ) );
| |
Obviously, there is no confusion over which company's compressor is used, because they have different names.
All these things work on different levels. As already indicated, namespaces work on the global, encapsulating level. Function overloading works within that outer level.
Finally, a note about logical organization. Just as the Alices were confused because they were two
different people with the same name -- you should not confuse two
different functions by giving them the same name. The
name of a thing is a strong indication of what that thing is/does. (You can safely assume that Alice is a girl.)
If you have a function "Get" that returns some random thing, how is that useful? You
must be explicit:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
class Vector
{
int x, y, z;
public:
int GetX() const { return x; }
int GetY() const { return y; }
int GetZ() const { return z; }
int Get( int index ) const
{
switch (index)
{
case 0: return x;
case 1: return y;
case 2: return z;
}
return 0;
}
};
| |
Hope this helps.