Topic : ANSI C++ Namespaces
Author : McMillan
Page : << Previous 3  
Go to page :


these functions with the scope resolution operator might confuse the lookup algorithm of the compiler; furthermore, doing so undermines the very idea of partitioning the global namespace. Therefore, it is recommended that you leave the scope resolution operator off the function's name.

Turning an External Function into A File-Local Function
In standard C, a nonlocal identifier that is declared to be static has internal linkage, which means that it is accessible only from within the translation unit (source file) in which it is declared (see also Chapter 2, "Standard Briefing: The Latest Addenda to ANSI/ISO C++"). This technique is used to support information hiding (as in the following example):

    //File hidden.c
static void decipher(FILE *f); // accessible only from within this file
    // now use this function in the current source file
decipher ("passwords.bin");
    //end of file


Although it is still supported in C++, this convention is now considered a deprecated feature. Future releases of your compiler might issue a warning message when they find a static identifier that is not a member of a class. In order to make a function accessible only from within its translation unit, use an unnamed namespace instead. The following example demonstrates the process:

//File hidden.cpp
namespace        //unnamed
{
  void decipher(FILE *f);  // accessible only from within this file
}
  //now use the function in the current source file.
  //No using declarations or directives are needed
decipher ("passwords.bin");


Although names in an unnamed namespace might have external linkage, they can never be seen from any other translation unit; the net effect of this is that the names of an unnamed namespace appear to have static linkage. If you declare another function with the same name in an unnamed namespace of another file, the two functions are hidden from one another, and their names do not clash.

Standard Headers Names
All Standard C++ header files now have to be included as follows:

#include <iostream> //note: no ".h" extension

That is, the .h extension is omitted. Standard C header files also obey this convention, with the addition of the letter c to their name. Therefore, a C standard header that was formerly named <xxx.h> is now <cxxx>. For example

#include <cassert> //formerly: <assert.h>  note the prefix 'c' and the //omission of  ".h"

The older convention for C headers, <xxx.h>, is still supported; however, it is now considered deprecated and, therefore, is not to not be used in new C++ code. The reason for this is that C <xxx.h> headers inject their declarations into the global namespace. In C++, however, most standard declarations are grouped under namespace std, as are the <cxxx> Standard C headers. No inference is to be drawn from the actual name convention that is used on the physical location of a header file or its underlying name. In fact, most implementations share a single physical file for the <xxx.h> and its corresponding <cxxx> notation. This is feasible due to some under-the-hood preprocessor tricks. Recall that you need to have a using declaration, a using directive, or a fully qualified name in order to access the declarations in the new style standard headers. For example

#include <cstdio>
using namespace std;  
void f()
{
    printf ("Hello World\n");
}


Restrictions on Namespaces
The C++ Standard defines several restrictions on the use of namespaces. These restrictions are meant to avert anomalies or ambiguities that can create havoc in the language.

Namespace std Can Not Be Modified
Generally, namespaces are open, so it is perfectly legal to expand existing namespaces with additional declarations and definitions across several files. The only exception to the rule is namespace std. According to the Standard, the result of modifying namespace std with additional declarations -- let alone the removal of existing ones -- yields undefined behavior, and is to be avoided. This restriction might seem arbitrary, but it's just common sense -- any attempt to tamper with namespace std undermines the very concept of a namespace dedicated exclusively to standard declarations.

User-Defined new and delete Cannot Be Declared in a Namespace
The Standard prohibits declarations of new and delete operators in a namespace. To see why, consider the following example:

char *pc; //global
namespace A
{
  void* operator new ( std::size_t );
  void operator delete ( void * );
  void func ()
  {
    pc = new char ( 'a'); //using A::new
  }
} //A
void f() { delete pc; } // call A::delete or //::delete?


Some programmers might expect the operator A::delete to be selected because it matches the operator new that was used to allocate the storage; others might expect the standard operator delete to be called because A::delete is not visible in function f(). By prohibiting declarations of new and delete in a namespace altogether, C++ avoids any such ambiguities.

Conclusions
Namespaces were the latest addition to the C++ Standard. Therefore, some compilers do not yet support this feature. However, all compiler vendors will incorporate namespace support in the near future. The importance of namespaces cannot be over-emphasized. As you have seen, any nontrivial C++ program utilizes components of the Standard Template Library, the iostream library, and other standard header files -- all of which are now namespace members.

Large-scale software projects can use namespaces cleverly to avoid common pitfalls and to facilitate version control, as you have seen.

C++ offers three methods for injecting a namespace constituent into the current scope. The first is a using directive, which renders all the members of a namespace visible in the current scope. The second is a using declaration, which is more selective and enables the injection of a single component from a namespace. Finally, a fully qualified name uniquely identifies a namespace member. In addition, the argument-dependent lookup, or Koenig lookup, captures the programmer's intention without forcing him or her to use wearying references to a namespace.

Page : << Previous 3