1. Trang chủ
  2. » Công Nghệ Thông Tin

Absolute C++ (4th Edition) part 46 ppsx

10 261 0

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 245,86 KB

Nội dung

11 Separate Compilation and Namespaces 11.1 SEPARATE COMPILATION 458 Encapsulation Reviewed 459 Header Files and Implementation Files 460 Example: DigitalTime Class 468 Tip: Reusable Components 469 Using #ifndef 469 Tip: Defining Other Libraries 472 11.2 NAMESPACES 473 Namespaces and using Directives 473 Creating a Namespace 475 Using Declarations 478 Qualifying Names 480 Example: A Class Definition in a Namespace 482 Tip: Choosing a Name for a Namespace 482 Unnamed Namespaces 484 Pitfall: Confusing the Global Namespace and the Unnamed Namespace 490 Tip: Unnamed Namespaces Replace the static Qualifier 491 Tip: Hiding Helping Functions 491 Nested Namespaces 491 Tip: What Namespace Specification Should You Use? 492 CHAPTER SUMMARY 495 ANSWERS TO SELF-TEST EXERCISES 495 PROGRAMMING PROJECTS 497 11 Separate Compilation and Namespaces From mine own library with volumes that I prize above my dukedom. William Shakespeare, The Tempest INTRODUCTION This chapter covers two topics that have to do with how to organize a C++ program into separate parts. Section 11.1 on separate compilation discusses how a C++ program can be distributed across a number of files so that when some parts of the program change only those parts need to be recompiled and so that the separate parts can be more easily reused in other applications. Section 11.2 discusses namespaces, which were introduced briefly in Chap- ter 1. Namespaces are a way of allowing you to reuse the names of classes, functions, and other items by qualifying the names to indicate different uses. Namespaces divide your code into sections so that the different sections may reuse the same names with differing meanings. They allow a kind of local meaning for names that is more general than local variables. This chapter can be covered earlier than its location in the book. This chap- ter does not use any of the material from Chapters 5 (arrays), 9 (strings), 10 (pointers and dynamic arrays) or Section 7.3 (vectors) of Chapter 7. Separate Compilation Your “if” is the only peacemaker; much virtue in “if.” William Shakespeare, As You Like It C++ has facilities for dividing a program into parts that are kept in separate files, compiled separately, and then linked together when (or just before) the program is run. You can place the definition for a class (and its associated function definitions) in files that are separate from the programs that use the class. In this way you can build up a library of classes so that many programs can use the same class. You can compile the class once and then use it in many different programs, just like you use the predefined libraries such as those with header files iostream and c stdlib . Moreover, you can define the class itself in two files so that the specification of what the class does is separate from how the class is implemented. If you only change the implementation of the class, 11.1 Separate Compilation 459 then you need only recompile the file containing the class implementation. The other files, including the files containing the programs that use the class, need not be changed or even recompiled. This section tells you how to carry out this separate compilation of classes. ■ ENCAPSULATION REVIEWED The principle of encapsulation says that you should separate the specification of how the class is used by a programmer from the details of how the class is implemented. The separation should be so complete that you can change the implementation without needing to change any program that uses the class. The way to ensure this separation can be summarized in three rules: 1. Make all the member variables private members of the class. 2. Make each of the basic operations for the class either a public member function of the class, a friend function, an ordinary function, or an overloaded operator. Group the class definition and the function and operator declarations (prototypes) together. This group, along with its accompanying comments, is called the interface for the class. Fully specify how to use each such function or operator in a comment given with the class or with the function or operator declaration. 3. Make the implementation of the basic operations unavailable to the programmer who uses the class. The implementation consists of the function definitions and overloaded operator definitions (along with any helping functions or other addi- tional items these definitions require). In C++, the best way to ensure that you follow these rules is to place the interface and the implementation of the class in separate files. As you might guess, the file that contains the interface is often called the interface file , and the file that contains the implementation is called the implementation file . The exact details of how to set up, compile, and use these files will vary slightly from one version of C++ to another, but the basic scheme is the same in all versions of C++. In particular, the details of what goes into the files is the same in all systems. The only things that vary are the com- mands used to compile and link these files. The details about what goes into these files are illustrated in the next subsection. A typical class has private member variables. Private member variables (and private member functions) present a problem to our basic philosophy of placing the interface and the implementation of a class in separate files. The public part of the definition for a class is part of the interface for the class, but the private part is part of the implemen- tation. This is a problem because C++ will not allow you to split the class definition across two files. Thus, some sort of compromise is needed. The only sensible compro- mise is to place the entire class definition in the interface file. Since a programmer who is using the class cannot use any of the private members of the class, the private mem- bers will, in effect, still be hidden from the programmer. interface implemen- tation interface file and implemen- tation file Private members are part of the imple- mentation. 460 Separate Compilation and Namespaces ■ HEADER FILES AND IMPLEMENTATION FILES Display 11.1 contains the interface file for a class called DigitalTime . DigitalTime is a class whose values are times of day, such as 9:30. Only the public members of the class are part of the interface. The private members are part of the implementation, even though they are in the interface file. The label private: warns you that these private members are not part of the public interface. Everything that a programmer needs to know in order to use the class DigitalTime is explained in the comment at the start of the file and in the comments in the public section of the class definition. As noted in the comment at the top of the interface file, this class uses 24-hour notation, so, for instance, 1:30 P.M. is input and output as 13:30. This and the other details you must know in order to effectively use the class DigitalTime are included in the comments given with the member functions. We have placed the interface in a file named dtime.h . The suffix .h indicates that this is a header file . An interface file is always a header file and so always ends with the suffix .h . Any program that uses the class DigitalTime must contain an include direc- tive like the following, which names this file: #include "dtime.h" When you write an include directive, you must indicate whether the header file is a predefined header file that is provided for you or is a header file that you wrote. If the header file is predefined, write the header file name in angular brackets, like <ios- tream> . If the header file is one that you wrote, write the header file name in quotes, like "dtime.h" . This distinction tells the compiler where to look for the header file. If the header file name is in angular brackets, the compiler looks wherever the predefined header files are kept in your implementation of C++. If the header file name is in quotes, the compiler looks in the current directory or wherever programmer-defined header files are kept on your system. Any program that uses our DigitalTime class must contain the above include direc- tive that names the header file dtime.h . That is enough to allow you to compile the program, but is not enough to allow you to run the program. In order to run the pro- gram you must write (and compile) the definitions of the member functions and the overloaded operators. We have placed these function and operator definitions in another file, which is called the implementation file . Although it is not required by most compilers, it is traditional to give the interface file and the implementation file the same name. The two files do, however, end in different suffixes. We have placed the interface for our class in the file named dtime.h and the implementation for our class in a file named dtime.cpp . The suffix you use for the implementation file depends on your version of C++. Use the same suffix for the implementation file as you normally use for files that contain C++ programs. (Other common suffixes are .cxx and .hxx .) The implementation file for our DigitalTime class is given in Display 11.2. After we explain how the various files for our class interact with each other, we will return to Display 11.2 and discuss the details of the definitions in this implementation file. header files include file names Separate Compilation 461 Display 11.1 Interface File for the DigitalTime Class 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 #include <iostream> 5 using namespace std; 6 class DigitalTime 7 { 8 public: 9 DigitalTime(int theHour, int theMinute); 10 DigitalTime( ); 11 //Initializes the time value to 0:00 (which is midnight). 12 getHour( ) const; 13 getMinute( ) const; 14 void advance(int minutesAdded); 15 //Changes the time to minutesAdded minutes later. 16 void advance(int hoursAdded, int minutesAdded); 17 //Changes the time to hoursAdded hours plus minutesAdded minutes later. 18 friend bool operator ==(const DigitalTime& time1, 19 const DigitalTime& time2); 20 friend istream& operator >>(istream& ins, DigitalTime& theObject); 21 friend ostream& operator <<(ostream& outs, const DigitalTime& theObject); 22 private: 23 int hour; 24 int minute; 25 static void readHour(int& theHour); 26 //Precondition: Next input to be read from the keyboard is 27 //a time in notation, like 9:45 or 14:45. 28 //Postcondition: theHour has been set to the hour part of the time. 29 //The colon has been discarded and the next input to be read is the minute. 30 static void readMinute(int& theMinute); 31 //Reads the minute from the keyboard after readHour has read the hour. 32 static int digitToInt(char c); 33 //Precondition: c is one of the digits ’0’ through ’9’. 34 //Returns the integer for the digit; for example, digitToInt(’3’) returns 3. 35 36 }; These member variables and helping functions are part of the implementation. They are not part of the interface. The word private indicates that they are not part of the public interface. 462 Separate Compilation and Namespaces Display 11.2 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 namespace std; 7 #include "dtime.h" 8 //Uses iostream and cstdlib: 9 DigitalTime::DigitalTime(int theHour, int theMinute) 10 { 11 if (theHour < 0 || theHour > 24 || theMinute < 0 || theMinute > 59) 12 { 13 cout << "Illegal argument to DigitalTime constructor."; 14 exit(1); 15 } 16 else 17 { 18 hour = theHour; 19 minute = theMinute; 20 } 21 if (hour == 24) 22 hour = 0; //Standardize midnight as 0:00 23 } 24 DigitalTime::DigitalTime( ) 25 { 26 hour = 0; 27 minute = 0; 28 } 29 int DigitalTime::getHour( ) const 30 { 31 return hour; 32 } 33 34 int DigitalTime::getMinute( ) const 35 { 36 return minute; 37 } 38 void DigitalTime::advance(int minutesAdded) 39 { 40 int grossMinutes = minute + minutesAdded; 41 minute = grossMinutes%60; 42 int hourAdjustment = grossMinutes/60; Separate Compilation 463 Display 11.2 Implementation File (part 2 of 3) 43 hour = (hour + hourAdjustment)%24; 44 } 45 void DigitalTime::advance(int hoursAdded, int minutesAdded) 46 { 47 hour = (hour + hoursAdded)%24; 48 advance(minutesAdded); 49 } 50 bool operator ==(const DigitalTime& time1, const DigitalTime& time2) 51 { 52 return (time1.hour == time2.hour && time1.minute == time2.minute); 53 } 54 //Uses iostream: 55 ostream& operator <<(ostream& outs, const DigitalTime& theObject) 56 { 57 outs << theObject.hour << ’:’; 58 if (theObject.minute < 10) 59 outs << ’0’; 60 outs << theObject.minute; 61 return outs; 62 } 63 64 //Uses iostream: 65 istream& operator >>(istream& ins, DigitalTime& theObject) 66 { 67 DigitalTime::readHour(theObject.hour); 68 DigitalTime::readMinute(theObject.minute); 69 return ins; 70 } 71 int DigitalTime::digitToInt(char c) 72 { 73 return ( int(c) - int(’0’) ); 74 } 75 //Uses iostream, cctype, and cstdlib: 76 void DigitalTime::readMinute(int& theMinute) 77 { 78 char c1, c2; 79 cin >> c1 >> c2; 80 if (!(isdigit(c1) && isdigit(c2))) 81 { 82 cout << "Error: illegal input to readMinute\n"; 83 exit(1); 84 } 464 Separate Compilation and Namespaces Display 11.2 Implementation File (part 3 of 3) 85 theMinute = digitToInt(c1)*10 + digitToInt(c2); 86 if (theMinute < 0 || theMinute > 59) 87 { 88 cout << "Error: illegal input to readMinute\n"; 89 exit(1); 90 } 91 } 92 93 //Uses iostream, cctype, and cstdlib: 94 void DigitalTime::readHour(int& theHour) 95 { 96 char c1, c2; 97 cin >> c1 >> c2; 98 if ( !( isdigit(c1) && (isdigit(c2) || c2 == ’:’ ) ) ) 99 { 100 cout << "Error: illegal input to readHour\n"; 101 exit(1); 102 } 103 if (isdigit(c1) && c2 == ’:’) 104 { 105 theHour = DigitalTime::digitToInt(c1); 106 } 107 else //(isdigit(c1) && isdigit(c2)) 108 { 109 theHour = DigitalTime::digitToInt(c1)*10 110 + DigitalTime::digitToInt(c2); 111 cin >> c2; //discard ’:’ 112 if (c2 != ’:’) 113 { 114 cout << "Error: illegal input to readHour\n"; 115 exit(1); 116 } 117 } 118 if (theHour == 24) 119 theHour = 0; //Standardize midnight as 0:00 120 if ( theHour < 0 || theHour > 23 ) 121 { 122 cout << "Error: illegal input to readHour\n"; 123 exit(1); 124 } 125 } Separate Compilation 465 Any file that uses the class DigitalTime must contain the include directive #include "dtime.h" Thus, both the implementation file and the program file must contain the include directive that names the interface file. The file that contains the program (that is, the file that contains the main function) is often called the application file or driver file. Display 11.3 contains an application file with a very simple program that uses and demonstrates the DigitalTime class. The exact details of how to run this complete program, which is contained in three files, depend on what system you are using. However, the basic details are the same for all systems. You must compile the implementation file and you must compile the appli- cation file that contains the main function. You do not compile the interface file, which in this example is the file dtime.h given in Display 11.1. You do not need to compile the interface file because the compiler thinks the contents of this interface file are already contained in each of the other two files. Recall that both the implementation file and the application file contain the directive #include "dtime.h" Compiling your program automatically invokes a preprocessor that reads this include directive and replaces it with the text in the file dtime.h . Thus, the compiler sees the contents of dtime.h , and so the file dtime.h does not need to be compiled separately. (In fact, the compiler sees the contents of dtime.h twice: once when you compile the implementation file and once when you compile the application file.) This copying of the file dtime.h is only a conceptual copying. The compiler acts as if the contents of dtime.h were copied into each file that has the include directive. However, if you look in those files after they are compiled, you will only find the include directive; you will not find the contents of the file dtime.h. Once the implementation file and the application file are compiled, you still need to connect these files so that they can work together. This is called linking the files and is done by a separate utility called a linker. The details of how to call the linker depends on what system you are using. Often, the command to run a program automatically invokes the linker, so you need not explicitly call the linker at all. After the files are linked, you can run your program. This sounds like a complicated process, but many systems have facilities that man- age much of this detail for you automatically or semiautomatically. On any system, the details quickly become routine. On UNIX systems, these details are handled by the make facility. In most IDEs (Integrated Development Environments) these various files are combined into something called a project. Displays 11.1, 11.2, and 11.3 contain one complete program divided into pieces and placed in three different files. You could instead combine the contents of these three files into one file, and then compile and run this one file without all this fuss application file or driver file compiling and running the program linking linker make project Why separate files? 466 Separate Compilation and Namespaces Display 11.3 Application File Using DigitalTime Class 1 //This is the application file timedemo.cpp, which demonstrates use of DigitalTime. 2 #include <iostream> 3 using namespace std; 4 #include "dtime.h" 5 int main( ) 6 { 7 DigitalTime clock, oldClock; 8 cout << "You may write midnight as either 0:00 or 24:00,\n" 9 << "but I will always write it as 0:00.\n" 10 << "Enter the time in 24-hour notation: "; 11 cin >> clock; 12 oldClock = clock; 13 clock.advance(15); 14 if (clock == oldClock) 15 cout << "Something is wrong."; 16 cout << "You entered " << oldClock << endl; 17 cout << "15 minutes later the time will be " 18 << clock << endl; 19 clock.advance(2, 15); 20 cout << "2 hours and 15 minutes after that\n" 21 << "the time will be " 22 << clock << endl; 23 return 0; 24 } S AMPLE D IALOGUE You may write midnight as either 0:00 or 24:00, but I will always write it as 0:00. Enter the time in 24-hour notation: 11:15 You entered 11:15 15 minutes later the time will be 11:30 2 hours and 15 minutes after that the time will be 13:45 . separate files. The public part of the definition for a class is part of the interface for the class, but the private part is part of the implemen- tation. This is a problem because C++ will not allow. how to organize a C++ program into separate parts. Section 11.1 on separate compilation discusses how a C++ program can be distributed across a number of files so that when some parts of the program. 458 Encapsulation Reviewed 459 Header Files and Implementation Files 460 Example: DigitalTime Class 468 Tip: Reusable Components 469 Using #ifndef 469 Tip: Defining Other Libraries 472 11.2 NAMESPACES

Ngày đăng: 04/07/2014, 05:21

TỪ KHÓA LIÊN QUAN