namespaces

A program includes many identifiers defined in different scopes. Sometimes a variable of one scope will "overlap" (i.e., collide) with a variable of the same name in a different scope, possibly creating a naming conflict. Such overlapping can occur at many levels. Identifier overlapping occurs frequently in third-party libraries that happen to use the same names for global identifiers (such as functions). This can cause compiler errors.

Good Programming Practice 24.1

Avoid identifiers that begin with the underscore character, which can lead to linker errors. Many code libraries use names that begin with underscores.

The C++ standard attempts to solve this problem with namespaces. Each namespace defines a scope in which identifiers and variables are placed. To use a namespace member, either the member's name must be qualified with the namespace name and the binary scope resolution operator (::), as in

MyNameSpace::member

or a using declaration or using directive must appear before the name is used in the program. Typically, such using statements are placed at the beginning of the file in which members of the namespace are used. For example, placing the following using directive at the beginning of a source-code file

using namespace MyNameSpace;

specifies that members of namespace MyNameSpace can be used in the file without preceding each member with MyNameSpace and the scope resolution operator (::).

A using declaration (e.g., using std::cout;) brings one name into the scope where the declaration appears. A using directive (e.g., using namespace std;) brings all the names from the specified namespace into the scope where the directive appears.

Software Engineering Observation 24.1

Ideally, in large programs, every entity should be declared in a class, function, block or namespace. This helps clarify every entity's role.


Error-Prevention Tip 24.2

Precede a member with its namespace name and the scope resolution operator (::) if the possibility exists of a naming conflict.

Not all namespaces are guaranteed to be unique. Two third-party vendors might inadvertently use the same identifiers for their namespace names. Figure 24.2 demonstrates the use of namespaces.

Figure 24.2. Demonstrating the use of namespaces.

(This item is displayed on pages 1204 - 1205 in the print version)

 1 // Fig. 24.2: fig24_02.cpp
 2 // Demonstrating namespaces.
 3 #include 
 4 using namespace std; // use std namespace
 5
 6 int integer1 = 98; // global variable
 7
 8 // create namespace Example 
 9 namespace Example 
10 { 
11  // declare two constants and one variable 
12  const double PI = 3.14159; 
13  const double E = 2.71828; 
14  int integer1 = 8; 
15 
16  void printValues(); // prototype 
17 
18  // nested namespace 
19  namespace Inner 
20  { 
21  // define enumeration 
22  enum Years { FISCAL1 = 1990, FISCAL2, FISCAL3 };
23  } // end Inner namespace 
24 } // end Example namespace 
25
26 // create unnamed namespace 
27 namespace 
28 { 
29  double doubleInUnnamed = 88.22; // declare variable
30 } // end unnamed namespace 
31
32 int main()
33 {
34 // output value doubleInUnnamed of unnamed namespace
35 cout << "doubleInUnnamed = " << doubleInUnnamed;
36
37 // output global variable
38 cout << "
(global) integer1 = " << integer1;
39
40 // output values of Example namespace
41 cout << "
PI = " << Example::PI << "
E = " << Example::E
42 << "
integer1 = " << Example::integer1 << "
FISCAL3 = "
43 << Example::Inner::FISCAL3 << endl;
44
45 Example::printValues(); // invoke printValues function
46 return 0;
47 } // end main
48
49 // display variable and constant values
50 void Example::printValues()
51 {
52 cout << "
In printValues:
integer1 = " << integer1 << "
PI = "
53 << PI << "
E = " << E << "
doubleInUnnamed = "
54 << doubleInUnnamed << "
(global) integer1 = " << ::integer1
55 << "
FISCAL3 = " << Inner::FISCAL3 << endl;
56 } // end printValues
 
 doubleInUnnamed = 88.22
 (global) integer1 = 98
 PI = 3.14159
 E = 2.71828
 integer1 = 8
 FISCAL3 = 1992

 In printValues:
 integer1 = 8
 PI = 3.14159
 E = 2.71828
 doubleInUnnamed = 88.22
 (global) integer1 = 98
 FISCAL3 = 1992
 

Using the std Namespace

Line 4 informs the compiler that namespace std is being used. The contents of header file are all defined as part of namespace std. [Note: Most C++ programmers consider it poor practice to write a using directive such as line 4 because the entire contents of the namespace are included, thus increasing the likelihood of a naming conflict.]

The using namespace directive specifies that the members of a namespace will be used frequently throughout a program. This allows the programmer to access all the members of the namespace and to write more concise statements such as

cout << "double1 = " << double1;

rather than

std::cout << "double1 = " << double1;

Without line 4, either every cout and endl in Fig. 24.2 would have to be qualified with std::, or individual using declarations must be included for cout and endl as in:

using std::cout;
using std::endl;

The using namespace directive can be used for predefined namespaces (e.g., std) or programmer-defined namespaces.


Defining Namespaces

Lines 924 use the keyword namespace to define namespace Example. The body of a namespace is delimited by braces ({}). Namespace Example's members consist of two constants (PI and E at lines 1213), an int (integer1 at line 14), a function (printValues at line 16) and a nested namespace (Inner at lines 1923). Notice that member integer1 has the same name as global variable integer1 (line 6). Variables that have the same name must have different scopesotherwise compilation errors occur. A namespace can contain constants, data, classes, nested namespaces, functions, etc. Definitions of namespaces must occupy the global scope or be nested within other namespaces.

Lines 2730 create an unnamed namespace containing the member doubleInUnnamed. The unnamed namespace has an implicit using directive, so its members appear to occupy the global namespace, are accessible directly and do not have to be qualified with a namespace name. Global variables are also part of the global namespace and are accessible in all scopes following the declaration in the file.

Software Engineering Observation 24.2

Each separate compilation unit has its own unique unnamed namespace; i.e., the unnamed namespace replaces the static linkage specifier.

 

Accessing Namespace Members with Qualified Names

Line 35 outputs the value of variable doubleInUnnamed, which is directly accessible as part of the unnamed namespace. Line 38 outputs the value of global variable integer1. For both of these variables, the compiler first attempts to locate a local declaration of the variables in main. Since there are no local declarations, the compiler assumes those variables are in the global namespace.

Lines 4143 output the values of PI, E, integer1 and FISCAL3 from namespace Example. Notice that each must be qualified with Example:: because the program does not provide any using directive or declarations indicating that it will use members of namespace Example. In addition, member integer1 must be qualified, because a global variable has the same name. Otherwise, the global variable's value is output. Notice that FISCAL3 is a member of nested namespace Inner, so it must be qualified with Example::Inner::.

Function printValues (defined at lines 5056) is a member of Example, so it can access other members of the Example namespace directly without using a namespace qualifier. The output statement in lines 5255 outputs integer1, PI, E, doubleInUnnamed, global variable integer1 and FISCAL3. Notice that PI and E are not qualified with Example. Variable doubleInUnnamed is still accessible, because it is in the unnamed namespace and the variable name does not conflict with any other members of namespace Example. The global version of integer1 must be qualified with the unary scope resolution operator (::), because its name conflicts with a member of namespace Example. Also, FISCAL3 must be qualified with Inner::. When accessing members of a nested namespace, the members must be qualified with the namespace name (unless the member is being used inside the nested namespace).

Common Programming Error 24.1

Placing main in a namespace is a compilation error.


Aliases for Namespace Names

Namespaces can be aliased. For example the statement

namespace CPPHTP5E = CPlusPlusHowToProgram5E;

creates the alias CPPHTP5E for CPlusPlusHowToProgram5E.


Introduction to Computers, the Internet and World Wide Web

Introduction to C++ Programming

Introduction to Classes and Objects

Control Statements: Part 1

Control Statements: Part 2

Functions and an Introduction to Recursion

Arrays and Vectors

Pointers and Pointer-Based Strings

Classes: A Deeper Look, Part 1

Classes: A Deeper Look, Part 2

Operator Overloading; String and Array Objects

Object-Oriented Programming: Inheritance

Object-Oriented Programming: Polymorphism

Templates

Stream Input/Output

Exception Handling

File Processing

Class string and String Stream Processing

Web Programming

Searching and Sorting

Data Structures

Bits, Characters, C-Strings and structs

Standard Template Library (STL)

Other Topics

Appendix A. Operator Precedence and Associativity Chart

Appendix B. ASCII Character Set

Appendix C. Fundamental Types

Appendix D. Number Systems

Appendix E. C Legacy Code Topics

Appendix F. Preprocessor

Appendix G. ATM Case Study Code

Appendix H. UML 2: Additional Diagram Types

Appendix I. C++ Internet and Web Resources

Appendix J. Introduction to XHTML

Appendix K. XHTML Special Characters

Appendix L. Using the Visual Studio .NET Debugger

Appendix M. Using the GNU C++ Debugger

Bibliography



C++ How to Program
C++ How to Program (5th Edition)
ISBN: 0131857576
EAN: 2147483647
Year: 2004
Pages: 627

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net