Namespaces 477 Note that you can have any number of these namespace groupings for a single namespace. In Display 11.5, we used two namespace groupings for namespace Space1 and two other groupings for namespace Space2. Every name defined in a namespace is available inside the namespace groupings, but the names can also be made available to code outside the namespace groupings. For example, the function declaration and function definition in the namespace Space1 can be made available with the using directive using namespace Space1 as illustrated in Display 11.5. Display 11.5 Namespace Demonstration (part 2 of 2) 26 27 namespace Space1 28 { 29 void greeting( ) 30 { 31 cout << "Hello from namespace Space1.\n"; 32 } 33 } 34 namespace Space2 35 { 36 void greeting( ) 37 { 38 cout << "Greetings from namespace Space2.\n"; 39 } 40 } 41 void bigGreeting( ) 42 { 43 cout << "A Big Global Hello!\n"; 44 } S AMPLE D IALOGUE Greetings from namespace Space2. Hello from namespace Space1. A Big Global Hello! 478 Separate Compilation and Namespaces Self-Test Exercises 6. Consider the program shown in Display 11.5. Could we use the name greeting in place of bigGreeting? 7. In Exercise 6, we saw that you could not add a definition for the following function to the global namespace: void greeting( ); Can you add a definition for the following function declaration to the global namespace? void greeting(int howMany ); ■ USING DECLARATIONS This subsection describes a way to qualify a single name so that you can make only one name from a namespace available to your program, rather than making all the names in a namespace available. We saw this technique in Chapter 1 and so this is a review and amplification of what we said in Chapter 1. Suppose you are faced with the following situation. You have two namespaces, NS1 and NS2. You want to use the function fun1 defined in NS1 and the function fun2 defined in namespace NS2. The complication is that both NS1 and NS2 also define a function myFunction. (Assume all functions in this discussion take no arguments, so overloading does not apply.) There is a problem with using namespace NS1; using namespace NS2; P UTTING A D EFINITION IN A N AMESPACE You place a name definition in a namespace by placing it in a namespace grouping , which has the following syntax: namespace Namespace_Name { Definition_1 Definition_2 . . . Definition_Last } You can have multiple namespace groupings (even in multiple files), and all the definitions in all the groupings will be in the same namespace. Namespaces 479 This would potentially provide conflicting definitions for myFunction. (If the name myFunction is never used, then most compilers will not detect the problem and will allow your program to compile and run.) What you need is a way to say you are using fun1 in namespace NS1 and fun2 in namespace NS2 and nothing else in the namespaces NS1 and NS2. We have already been using a technique that can handle this situation. The following is your solution: using NS1::fun1; using NS2::fun2; A qualification of the form using Name_Space :: One_Name ; makes the (definition of the) name One_Name from the namespace Name_Space available, but does not make any other names in Name_Space available. This is called a using declaration. Note that the scope resolution operator :: that we use in these using declarations is the same as the scope resolution operator we use when defining member functions. These two uses of the scope resolution operator have a similarity. For example, Display 11.2 had the following function definition: void DigitalTime::advance(int hoursAdded, int minutesAdded) { hour = (hour + hoursAdded)%24; advance(minutesAdded); } In this case the :: means that we are defining the function advance for the class Digi- talTime , as opposed to any other function named advance in any other class. Similarly, using NS1::fun1; means we are using the function named fun1 as defined in the namespace NS1, as opposed to any other definition of fun1 in any other namespace. There are two differences between a using declaration, such as using std::cout; and a using directive such as using namespace std; The differences are: 1. A a using declaration makes only one name in the namespace available to your code, while a using directive makes all the names in a namespace available. 2. A using declaration introduces a name (like cout) into your code so no other use of the name can be made. However, a using directive only potentially introduces the names in the namespace. using NS1::fun1; using declaration 480 Separate Compilation and Namespaces Point 1 is pretty obvious. Point 2 has some subtleties. For example, suppose the namespaces NS1 and NS2 both provide definitions for myFunction, but have no other name conflicts, then the following will produce no problems: using namespace NS1; using namespace NS2; provided that (within the scope of these directives) the conflicting name myFunction is never used in your code. On the other hand, the following is illegal, even if the function myFunction is never used: using NS1::myFunction; using NS2::myFunction; Sometimes this subtle point can be important, but it does not impinge on most rou- tine code. So, we will often use the term using directive loosely to mean either a using directive or a using declaration. ■ QUALIFYING NAMES This section introduces a way to qualify names that we have not discussed before. Suppose that you intend to use the name fun1 as defined in the namespace NS1, but you only intend to use it one time (or a small number of times). You can name the function (or other item) using the name of the namespace and the scope resolution operator as follows: NS1::fun1( ); This form is often used when specifying a parameter type. For example, consider int getInput(std::istream inputStream) . . . In the function getInput, the parameter inputStream is of type istream, where istream is defined as in the std namespace. If this use of the type name istream is the only name you need from the std namespace (or if all the names you need are similarly qualified with std::), then you do not need using namespace std; or using std::istream; Note that you can use std::istream even within the scope of a using directive for another namespace which also defines the name istream. In this case std::istream and istream will have different definitions. For example, consider using namespace MySpace; void someFunction(istream p1, std::istream p2); using directive Namespaces 481 Self-Test Exercises Assuming istream is a type defined in the namespace MySpace, then p1 will have the type istream as defined in MySpace and p2 will have the type istream as defined in the std namespace. 8. What is the output produced by the following program? #include <iostream> using namespace std; namespace Hello { void message( ); } namespace GoodBye { void message( ); } void message( ); int main( ) { using GoodBye::message; { using Hello::message; message( ); GoodBye::message( ); } message( ); return 0; } void message( ) { cout << "Global message.\n"; } namespace Hello { void message( ) { 482 Separate Compilation and Namespaces Tip Example cout << "Hello.\n"; } } namespace GoodBye { void message( ) { cout << "Good-Bye.\n"; } } 9. Write the declaration (prototype) for a void function named wow. The function wow has two parameters, the first of type speed as defined in the speedway namespace and the sec- ond of type speed as defined in the indy500 namespace. A C LASS D EFINITION IN A N AMESPACE In Displays 11.6 and 11.7 we have again rewritten both the header file dtime.h for the class Digi- talTime and the implementation file for the class DigitalTime. This time (no pun intended), we have placed the definition in a namespace called DTimeSavitch. Note that the namespace DTimeSavitch spans the two files dtime.h and dtime.cpp. A namespace can span multiple files. If you rewrite the definition of the class DigitalTime as shown in Displays 11.6 and 11.7, then the application file in Display 11.3 needs to specify the namespace DTimeSavitch in some way, such as the following: using namespace DTimeSavitch; or using DTimeSavitch::DigitalTime; C HOOSING A N AME FOR A N AMESPACE It is a good idea to include your last name or some other unique string in the names of your namespaces so as to reduce the chance that somebody else will use the same namespace name as you do. With multiple programmers writing code for the same project, it is important that namespaces that are meant to be distinct really do have distinct names. Otherwise, you can easily have multiple definitions of the same names in the same scope. That is why we included the name Savitch in the namespace DtimeSavitch in Display 11.9. Namespaces 483 Display 11.6 Placing a Class in a Namespace (Header File) 1 //This is the header file dtime.h. 2 #ifndef DTIME_H 3 #define DTIME_H 4 #include <iostream> 5 using std::istream; 6 using std::ostream; 7 namespace DTimeSavitch 8 { 9 10 class DigitalTime 11 { 12 13 < The definition of the class DigitalTime is the same as in Display 11.1. > 14 }; 15 16 }// DTimeSavitch 17 #endif //DTIME_H A better version of this class definition will be given in Displays 11.8 and 11.9. Note that the namespace DTimeSavitch spans two files. The other is shown in Display 11.7. Display 11.7 Placing a Class in a Namespace (Implementation File) 1 //This is the implementation file dtime.cpp. 2 #include <iostream> 3 #include <cctype> 4 #include <cstdlib> 5 using std::istream; 6 using std::ostream; 7 using std::cout; 8 using std::cin; 9 #include "dtime.h" 10 namespace DTimeSavitch 11 { 12 13 <All the function definitions from Display 11.2 go here.> 14 15 }// DTimeSavitch You can use the single using directive using namespace std; in place of these four using declarations. However, the four using declarations are a preferable style. 484 Separate Compilation and Namespaces ■ UNNAMED NAMESPACES A compilation unit is a file, such as a class implementation file, along with all the files that are #included in the file, such as the interface header file for the class. Every com- pilation unit has an unnamed namespace. A namespace grouping for the unnamed namespace is written in the same way as for any other namespace, but no name is given, as in the following example: namespace { void sampleFunction( ) . . . } //unnamed namespace All the names defined in the unnamed namespace are local to the compilation unit, and so the names can be reused for something else outside the compilation unit. For example, Displays 11.8 and 11.9 show a rewritten (and final) version of the interface compilation unit Display 11.8 Hiding the Helping Functions in a Namespace (Interface File) (part 1 of 2) 1 //This is the header file dtime.h. This is the interface for the class DigitalTime. 2 //Values of this type are times of day. The values are input and output in 24-hour 3 //notation, as in 9:30 for 9:30 AM and 14:45 for 2:45 PM. 4 #ifndef DTIME_H 5 #define DTIME_H 6 #include <iostream> 7 using std::istream; 8 using std::ostream; 9 namespace DTimeSavitch 10 { 11 class DigitalTime 12 { 13 public: 14 DigitalTime(int theHour, int theMinute); 15 DigitalTime( ); 16 //Initializes the time value to 0:00 (which is midnight). 17 getHour( ) const; 18 getMinute( ) const; 19 void advance(int minutesAdded); 20 //Changes the time to minutesAdded minutes later. This is our final version of the class DigitalTime. This is the best version and the one you should use. The implementation to use with this interface is given in Display 11.9. Namespaces 485 Display 11.8 Hiding the Helping Functions in a Namespace (Interface File) (part 2 of 2) 21 void advance(int hoursAdded, int minutesAdded); 22 //Changes the time to hoursAdded hours plus minutesAdded minutes later. 23 friend bool operator ==(const DigitalTime& time1, 24 const DigitalTime& time2); 25 friend istream& operator >>(istream& ins, DigitalTime& theObject); 26 friend ostream& operator <<(ostream& outs, 27 const DigitalTime& theObject); 28 private: 29 int hour; 30 int minute; 31 }; 32 } //DTimeSavitch 33 #endif //DTIME_H Note that the helping functions are not mentioned in the interface file. Display 11.9 Hiding the Helping Functions in a Namespace (Implementation File) (part 1 of 3) 1 //This is the implementation file dtime.cpp of the class DigitalTime. 2 //The interface for the class DigitalTime is in the header file dtime.h. 3 #include <iostream> 4 #include <cctype> 5 #include <cstdlib> 6 using std::istream; 7 using std::ostream; 8 using std::cout; 9 using std::cin; 10 #include "dtime.h" 11 namespace 12 { 13 int digitToInt(char c) 14 { 15 return ( int(c) - int(’0’) ); 16 } 17 //Uses iostream, cctype, and cstdlib: 18 void readMinute(int& theMinute) 19 { 20 char c1, c2; 21 cin >> c1 >> c2; 22 if (!(isdigit(c1) && isdigit(c2))) 23 { 24 cout << "Error: illegal input to readMinute\n"; Specifies the unnamed namespace Names defined in the unnamed namespace are local to the compilation unit. So, these helping functions are local to the file dtime.cpp. 486 Separate Compilation and Namespaces Display 11.9 Hiding the Helping Functions in a Namespace (Implementation File) (part 2 of 3) 25 exit(1); 26 } 27 theMinute = digitToInt(c1)*10 + digitToInt(c2); 28 if (theMinute < 0 || theMinute > 59) 29 { 30 cout << "Error: illegal input to readMinute\n"; 31 exit(1); 32 } 33 } 34 35 //Uses iostream, cctype, and cstdlib: 36 void readHour(int& theHour) 37 { 38 char c1, c2; 39 cin >> c1 >> c2; 40 if ( !( isdigit(c1) && (isdigit(c2) || c2 == ’:’ ) ) ) 41 { 42 cout << "Error: illegal input to readHour\n"; 43 exit(1); 44 } 45 if (isdigit(c1) && c2 == ’:’) 46 { 47 theHour = digitToInt(c1); 48 } 49 else //(isdigit(c1) && isdigit(c2)) 50 { 51 theHour = digitToInt(c1)*10 + digitToInt(c2); 52 cin >> c2; //discard ’:’ 53 if (c2 != ’:’) 54 { 55 cout << "Error: illegal input to readHour\n"; 56 exit(1); 57 } 58 } 59 if (theHour == 24) 60 theHour = 0; //Standardize midnight as 0:00. 61 if ( theHour < 0 || theHour > 23 ) 62 { . with this interface is given in Display 11.9. Namespaces 485 Display 11.8 Hiding the Helping Functions in a Namespace (Interface File) (part 2 of 2) 21 void advance(int hoursAdded, int minutesAdded); 22. functions are local to the file dtime.cpp. 486 Separate Compilation and Namespaces Display 11.9 Hiding the Helping Functions in a Namespace (Implementation File) (part 2 of 3) 25 exit(1); 26 } 27 theMinute. namespace MySpace; void someFunction(istream p1, std::istream p2); using directive Namespaces 481 Self-Test Exercises Assuming istream is a type defined in the namespace MySpace, then p1 will