Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old May 7th, 2010, 5:54 AM   #1
DaWei
Resident Grouch
 
DaWei's Avatar
 
Join Date: Jun 2005
Posts: 8,368
Rep Power: 21 DaWei will become famous soon enoughDaWei will become famous soon enough
Namespaces

This is an article written by Grumpy, a member of this forum. It was originally posted in another forum. Said forum then moved it into an area where Grumpy could not maintain it. So far as I know, there haven't been any suggestions regarding errors, either typographical or otherwise. The mods may want to look it over and then move it to the tutorials section.

Namespaces and the "using" directive

This is a repost (with additions/corrections) of my response to a query about namespaces in the main forum. Some others suggested I add this to the FAQ, so....

Namespaces and their close ally, the using directive, have a dubious distinction of being features of the C++ language that most programmers employ, while also being on the list of features that are most often misunderstood and misused.

The following is a partial (and probably imperfect) attempt to describe what namespaces are in C++, and some forms of the "using" directive. Over time I may edit this post to make the discussion more complete (eg discuss the various gotcha's that arise from misunderstanding how namespaces work) or make corrections. If people pick up errors, or want to suggest additional material to include here, send me a private message.

In simple terms, namespaces are a means of grouping the names of things..... by "things" I include type declarations, function names, type definitions, object names, etc etc. Consider an application that is built using several libraries that were written independently by other developers. In this case, the odds of two libraries using the same name for different things increases substantially. For example, a library concerned with multithreading might provide a class named Thread, which is responsible for creating an operating system thread and executing some function in the context of that thread. Now, let's consider an application that will do things multithreaded, but the actual purpose of that application is to control a set of sewing machines. The application therefore needs to use another library that also happens to define a class called Thread. Without namespaces, it would not be (easily) possible to use both libraries in the same application [there are techniques, but they are pretty arcane, particularly if our application developer cannot access source code for one or both libraries]. This is formally (according to the C++ standard) a violation of the "one definition rule" --- there should only be one definition of class Thread, not two. In practice, one might sometimes get lucky (eg our two hypothetical Thread classes might have all member functions with different names), but if both classes have a member function of the same name (eg both declare a non-static function of the form "void Initialise()") it is tricky even convincing the compiler and linker to build the application, let alone being able to run it.

The purpose of namespaces is to reduce the odds that logically unrelated things wind up with exactly the same name. In our example, the developer of the multithreading library might define a namespace called Multithreading, while the developer of the other library may define a namespace named Cotton, viz.
PHP Code:
// in the header files and implementation of operating system theads ....
namespace Multithreading
{
// all the definitions and declarations related to operating system threads
}

// ... and in the header related to doing stuff with cotton ...

namespace Cotton
{
// all the definitions and declarations related manipulating cotton threads
}

The actual names of the namespaces don't matter, as long as they are different. The C++ standard defines a namespace named std, into which everything in the standard library exists (and application developers are not allowed to insert things into that namespace). Third party library developers pick the names of namespaces in various ways to reduce the odds of clashing with other libraries (eg by embedding their company name in the namespace name). Technically, this doesn't eliminate the possibility of duplicating names (eg two different library developers might happen to choose exactly the same name for their namespace), but the odds of it happening are substantially reduced.

One nice thing about namespaces is they can be nested. For example, the Multithreading namespace I'm using in this example might include, within it, another namespace named Synchronisation which defines things related to mutexes and critical sections. Another feature is that everything within a class (or struct) definition appears in a namespace of the same name as the class. So the fully qualified (or fully scoped) name of a class related to critical sections might be something like "Multithreading:ynchronisation::CriticalSection", meaning that CriticalSection is a name within a namespace called Synchronisation, which is in turn within a namespace called Multithreading.

This is all fine and dandy, but having to use the fully scoped name of an object or type gets inconvenient. For example, if we use the standard string class, every time we use a string, we have to name it std::string. Programmers are lazy souls (even worse than mathematicians, but mathematicians are taught to be deliberately lazy), so they whinge about having to do this in code where they don't use any other string class. This results in various forms of the "using" keyword.

The most common one seen (and the one which I would argue should be used less) is.
PHP Code:
using namespace std;

takes everything that is declared or defined in namespace std, and allows them to be used without explicitly prefixing them with "std::".

One (of many) problems with doing this is shown in this example;
PHP Code:
#include <string>
// from another header ...
namespace Foo
{
class string
{
// whatever
};
}

// now try to use our strings

using namespace std;
using namespace Foo;

int main()
{
string x; // compiler complaint due to ambiguity
// (not possible to decide what string to use).
}

The string declaration within main() potentially resolves to either std::string or Foo::string. And there is no reason for the compiler to prefer one over the other....

This is one reason (of several) that "using namespace" directives are often frowned upon.....they can give unintended effects such as code that can't be compiled because it is ambiguous. Putting a "using namespace" directive into any header file is bad practice, because it means every source file that #include's that header file has the chance of encountering this sort of ambiguity. And the only fix for such ambiguity is for the programmer to only use fully scoped names (eg "std::string" rather than "string" in the above example).

Another form of a using directive is
PHP Code:
using std::string;

which basically allows definitions associated with std::string to be used, without pulling everything in namespace std along for the ride.

Another use of the using keyword is to get around the "hiding rule", which is designed (deliberately, for reasons I won't go into here) to catch programmers out who do this;
PHP Code:
class Base
{
public:
void Foo(int);
};

class Derived: public Base
{
public:
void Foo(double);
};

int main()
{
Derived x;
x.Foo(1); // will cause a compiler error, as Foo(int) is hidden
}

If the intent in this example is for class Derived to supply both a Foo(int) and a Foo(double), the definition of Derived may be changed to....
PHP Code:
class Derived: public Base
{
public:
using Base::Foo;
void Foo(double);
};

Note that, in this case, the "using" directive is local to class Derived.

A common misunderstanding of the using directive and namespaces is shown in the following example;
PHP Code:
#include <iostream>
using namespace std;

class Foo
{
// various other details

friend ostream & operator<<(ostream &, const Foo &);
};

int main()
{
Foo x;
cout << x;
}

Most novices believe that the above will work, and output the object x to the standard stream std::cout. Even worse, some text books (which I won't name) encourage that belief. The result, however, is usually a compile time error. Worse still, some compilers also get it wrong, and don't complain---leaving a user mystified about why x is not output to standard output.

This example is problematical because the "using namespace" directive does not interact with the friend declaration (except with some buggy compilers) in the "obvious" way. The friend declaration is actually equivalent to
PHP Code:
friend ::ostream &operator<<(::ostream &, const Foo &);

whereas the programmer (because they have used the "using namespace" directive) thinks it is "obviously" equivalent to;
PHP Code:
friend std::ostream &operator<<(std::ostream &, const Foo &);

The first form has actually (implicitly) declared a type named ostream in the (unnamed) global namespace, and then declared an operator<<() that works with that implicitly declared type. The problem is, the type ::ostream is completely distinct from std::ostream. When we come to use it, in the line
PHP Code:
cout << x;

the compiler realises that cout is actually std::cout (thanks to the using directive) and then looks for an implementation of the corresponding operator<<() that works with a std::ostream on the left hand side and a Foo on the right. Our function "::ostream &operator<<(::ostream &, const Foo &)" does not satisfy that search, so a compile time error occurs.

In practice, to make the above example work, I would suggest never employing the "using namespace" directive in a header file or before any class declaration. Instead, I would do this;
PHP Code:
#include <iostream>

// the following may be in a header file
class Foo
{
// various other details

friend std::ostream & operator<<(std::ostream &, const Foo &);
};

// OK, in our executing code we want to be lazy

using namespace std;

int main()
{
Foo x;
cout << x;
}

This form also (thankfully) works as intended, even with compilers out there that handle the first form incorrectly.
__________________
Contributor's Corner:
Politically Incorrect
DaWei on Pointers
DaWei is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
The Basics * Methods, Classes, & Namespaces? MWelch C# 3 May 20th, 2009 3:24 PM
Are #define allowed inside namespaces? aznluvsmc C++ 3 Apr 1st, 2006 8:40 PM
namespaces, unexplored territory melbolt C++ 0 Feb 15th, 2005 9:32 PM




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 10:01 AM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC