Monday, August 22, 2011

Namespaces in C++ and C

In C and C++ there is one global scope that contains
  1. The names of all global functions and variables
  2. Class and type names that are commonly available to all programs.

Classes are one way of grouping names (members) under a common heading (the classname), but sometimes it is desirable to have a higher level grouping of names.
The namespace mechanism provides a way to partition the global scope into individually named sub-scopes. This helps avoid naming conflicts that can arise when developing a program that uses modules with name conflicts.

The syntax for defining a namespace is

namespace namespaceName { decl1, decl2, ...}

Any legal identifier can be used for the optional namespaceName.

Examples ‘a’ and ‘b’ define two separate namespaces in different files, each containing functions with the same name.

/*
 * Example ‘a’
 * a.h
 */
 #include <iostream>
 namespace A {
    using namespace std;
    void f() {
       cout << "f from A\n";
    }
    void g() {
       cout << "g from A\n";
    }
 }

/*
 * Example ‘b’
 * b.h
 */
 #include <iostream>
 namespace B {
    using namespace std;
    void f() {
       cout << "f from B\n";
    }
    void g() {
       cout << "g from B\n";
    }
 }

Example c includes both header files and uses scope resolution to call functions declared in either file.
/*
 * Example ‘c’
 * namespace.cpp
 */
 #include "a.h"
 #include "b.h"

 #include <iostream>

 int main() {
    A::f();
    B::g();
    return 0;
 }
/*
 [sgupta@rhel55x86 namespaces]$ c++ -o namespace namespace.cpp
 [sgupta@rhel55x86 namespaces]$ ./namespace
 f from A
 g from B
 [sgupta@rhel55x86 namespaces]$
*/

The using keyword permits individual members of a namespace to be referenced without scoping. The syntax can take two forms.
  1. The using directive: using namespace namespaceName—imports the entire namespace into the current scope
  2. The using declaration: using namespaceName::identifier—imports a particular identifier from that namespace.

Care must be exercised to make sure that ambiguities are not produced when identifiers are present in more than one included namespace.We show an example of such an ambiguous function call in Example d.

/*
 * Example ‘c’
 * namespace2.cpp
 */
 #include "a.h"
 #include "b.h"

 #include <iostream>

 int main() {
    using A::f;        //declaration—brings A::f() into scope
    f();
   
    using namespace B; //directive—brings all of B into scope
    g();               // okay
    f();               // ambiguous
    return 0;
 }
/*
 [sgupta@rhel55x86 namespaces]$ c++ -o namespace2 namespace2.cpp
 [sgupta@rhel55x86 namespaces]$ ./namespace2
 f from A
 g from B
 f from A
 [sgupta@rhel55x86 namespaces]$
*/

TIP:
NAMESPACE ALIASES To make the names of various namespaces
unique, programmers sometimes produce extremely long namespace
names. One can easily introduce an alias for a long namespace name
with a command such as:
namespace xyz = verylongcomplicatednamespacename;

Anonymous Namespaces
A namespace without a name is an anonymous namespace. This is similar to static global, or file scope identifier. It is accessible from that point down to the end of the file.Example ‘e’ shows how anonymous namespaces can eliminate the need for static globals.
/*
 * Example ‘e’
 * anonymouse.h
 */

 namespace {
    const int MAXSIZE = 256;
 }
 void f1() {
    int s[MAXSIZE];
 }

Open Namespaces
Any namespace definition is open in the sense that you can add members to an existing namespace by declaring a second namespace with the same name but with new items. The new items will be appended to the namespace in the order in which the namespace declarations are encountered by the compiler.
Classes are similar to namespaces but classes are not open because they serve as a pattern for the creation of objects.
The using directive does not extend the scope in which it is used; it imports names from the specified namespace into the current scope.
Names locally defined take precedence over names from the namespace (which are still accessible using the scope resolution operator).

Namespace, static Objects and extern
Objects declared inside namespaces are implicitly static, meaning that they are created once for the entire application. The initialization of a static object must exist in only one C++ module. To declare a static object (global or namespace) without defining it, use the keyword extern.
Example ‘f’ shows how to declare namespace variables.

/*
 * Example ‘f’
 */
[ . . . . ]
namespace qstd {
   extern QTextStream cin; // declared only—defined in the .cpp file
   extern QTextStream cout;
   extern QTextStream cerr;
   bool yes(QString yesNoQuestion);
   bool more(QString prompt);
   int promptInt(int base = 10);
   double promptDouble();
   void promptOutputFile(QFile& outfile);
   void promptInputFile(QFile& infile);
[ . . . . ] 


Each variable must be defined in a .cpp file, as shown in Example ‘g’

/*
 * Example ‘g’
 * qstd.cpp
 */
[ . . . . ]
QTextStream qstd::cin(stdin, QIODevice::ReadOnly);
QTextStream qstd::cout(stdout, QIODevice::WriteOnly);
QTextStream qstd::cerr(stderr, QIODevice::WriteOnly);


No comments:

Post a Comment