Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 40 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
40
Dung lượng
371,28 KB
Nội dung
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 { Namespaces 487 Display 11.9 Hiding the Helping Functions in a Namespace (Implementation File) (part 3 of 3) 63 cout << "Error: illegal input to readHour\n"; 64 exit(1); 65 } 66 } 67 } //unnamed namespace 68 69 namespace DTimeSavitch 70 { 71 //Uses iostream: 72 istream& operator >>(istream& ins, DigitalTime& theObject) 73 { 74 readHour(theObject.hour); 75 readMinute(theObject.minute); 76 return ins; 77 } 78 ostream& operator <<(ostream& outs, const DigitalTime& theObject) < The body of the function definition is the same as in Display 11.2. > 79 bool operator ==(const DigitalTime& time1, const DigitalTime& time2) < The body of the function definition is the same as in Display 11.2. > 80 DigitalTime::DigitalTime(int theHour, int theMinute) < The body of the function definition is the same as in Display 11.2. > 81 DigitalTime::DigitalTime( ) < The body of the function definition is the same as in Display 11.2. > 82 int DigitalTime::getHour( ) const < The body of the function definition is the same as in Display 11.2. > 83 int DigitalTime::getMinute( ) const < The body of the function definition is the same as in Display 11.2. > 84 void DigitalTime::advance(int minutesAdded) < The body of the function definition is the same as in Display 11.2. > 85 void DigitalTime::advance(int hoursAdded, int minutesAdded) < The body of the function definition is the same as in Display 11.2. > 86 } //DTimeSavitch Within the compilation unit (in this case dtime.cpp), you can use names in the unnamed namespace without qualification. 488 Separate Compilation and Namespaces and implementation file for the class DigitalTime. Note that the helping functions readHour, readMinute, and digitToInt are all in the unnamed namespace; thus they are local to the compilation unit. As illustrated in Display 11.10, the names in the unnamed namespace can be reused for something else outside the compilation unit. In Display 11.10, the function name readHour is reused for a different function in the application program. Display 11.10 Hiding the Helping Functions in a Namespace (Application Program) (part 1 of 2) 1 //This is the application file timedemo.cpp. This program 2 //demonstrates hiding the helping functions in an unnamed namespace. 3 #include <iostream> 4 #include "dtime.h" 5 void readHour(int& theHour); 6 int main( ) 7 { 8 using std::cout; 9 using std::cin; 10 using std::endl; 11 using DTimeSavitch::DigitalTime; 12 int theHour; 13 readHour(theHour); 14 DigitalTime clock(theHour, 0), oldClock; 15 oldClock = clock; 16 clock.advance(15); 17 if (clock == oldClock) 18 cout << "Something is wrong."; 19 cout << "You entered " << oldClock << endl; 20 cout << "15 minutes later the time will be " 21 << clock << endl; 22 clock.advance(2, 15); 23 cout << "2 hours and 15 minutes after that\n" 24 << "the time will be " 25 << clock << endl; 26 return 0; 27 } If you place the using declarations here, then the program behavior will be the same. However, many authorities say that you should make the scope of each using declaration or using directive as small as is reasonable, and we wanted to give you an example of that technique. This is a different function readHour than the one in the implementation file dtime.cpp (shown in Display 11.9). Namespaces 489 If you look again at the implementation file Display 11.9, you will see that the help- ing functions digitToInt, readHour, and readMinute are used outside the unnamed namespace without any namespace qualifier. Any name defined in the unnamed name- space can be used without qualification anywhere in the compilation unit. (Of course, this needed to be so, since the unnamed namespace has no name to use for qualifying its names.) It is interesting to note how unnamed namespaces interact with the C++ rule that you cannot have two definitions of a name in the same namespace. There is one unnamed namespace in each compilation unit. It is easily possible for compilation units to overlap. For example, both the implementation file for a class and an applica- tion program using the class would normally both include the header file (interface file) for the class. Thus, the header file is in two compilation units and hence participates in two unnamed namespaces. As dangerous as this sounds, it will normally produce no problems as long as each compilation unit’s namespace makes sense when considered by itself. For example, if a name is defined in the unnamed namespace in the header Display 11.10 Hiding the Helping Functions in a Namespace (Application Program) (part 2 of 2) 28 29 void readHour(int& theHour) 30 { 31 using std::cout; 32 using std::cin; 33 34 cout << "Let's play a time game.\n" 35 << "Let's pretend the hour has just changed.\n" 36 << "You may write midnight as either 0 or 24,\n" 37 << "but, I will always write it as 0.\n" 38 << "Enter the hour as a number (0 to 24): "; 39 cin >> theHour; 40 } S AMPLE D IALOGUE Let's play a time game. Let's pretend the hour has just changed. You may write midnight as either 0 or 24, but, I will always write it as 0. Enter the hour as a number (0 to 24): 11 You entered 11:00 15 minutes later the time will be 11:15 2 hours and 15 minutes after that the time will be 13:30 When we gave these using declarations before, they were in main, so their scope was main. Thus, we need to repeat them here in order to use cin and cout in readHour. [...]... ios::app); 12 13 fout . use for qualifying its names.) It is interesting to note how unnamed namespaces interact with the C++ rule that you cannot have two definitions of a name in the same namespace. There is one unnamed. example. Namespaces 491 Tip Tip U NNAMED N AMESPACES R EPLACE THE static Q UALIFIER Earlier versions of C++ used the qualifier static to make a name local to a file. This use of static is being phased. different than placing all definitions in the global namespace, which is what earlier versions of C++ actually did. So, this approach gets no value from the namespace mechanism. (If you place such