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

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

10 262 0
Tài liệu đã được kiểm tra trùng lặp

Đ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

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

11 Separate Compilation and Namespaces11.1 SEPARATE COMPILATION 458 Encapsulation Reviewed 459 Header Files and Implementation Files 460 Example: DigitalTime Class 468 Tip: Reusable Comp

Trang 1

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

Trang 2

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 machap-terial from Chapchap-ters 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 cstdlib 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

Trang 3

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.

Trang 4

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

Trang 5

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.

Trang 6

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 {

20 }

21 if (hour == 24)

22 hour = 0; //Standardize midnight as 0:00

23 }

24 DigitalTime::DigitalTime( )

25 {

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;

Trang 7

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";

84 }

Trang 8

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";

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";

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 ’:’

113 {

114 cout << "Error: illegal input to readHour\n";

115 exit(1);

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";

124 }

125 }

Trang 9

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?

Trang 10

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

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

TỪ KHÓA LIÊN QUAN