Absolute C++ (4th Edition) part 25 docx

10 202 0
Absolute C++ (4th Edition) part 25 docx

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

Thông tin tài liệu

Classes 243 A programmer who uses a class also should not need to know how the data of the class is implemented. The implementation of the data should be as hidden as the imple- mentation of the member functions. In fact, it is close to impossible to distinguish between hiding the implementation of the member functions and the implementation of the data. To a programmer, the class DayOfYear (Display 6.3) has dates as data, not numbers. The programmer should not know or care whether the month March is implemented as the int value 3, the quoted string "March", or in some other way. Defining a class so that the implementation of the member functions and the imple- mentation of the data in objects are not known, or is at least irrelevant, to the program- mer who uses the class is known by a number of different terms. The most common terms used are information hiding, data abstraction, and encapsulation, each of which means that the details of the implementation of a class are hidden from the pro- grammer who uses the class. This principle is one of the main tenets of object-oriented programming (OOP). When discussing OOP, the term that is used most frequently is encapsulation. One of the ways to apply this principle of encapsulation to your class definitions is to make all member variables private, which is what we discuss in the next subsection. ■ PUBLIC AND PRIVATE MEMBERS Look back at the definition of the type DayOfYear given in Display 6.3. In order to use that class, you need to know that there are two member variables of type int that are named month and day. This violates the principle of encapsulation (information hiding) that we discussed in the previous subsection. Display 6.4 is a rewritten version of the class DayOfYear that better conforms to this encapsulation principle. Notice the words private: and public: in Display 6.4. All the items that follow the word private: (in this case the member variables month and day) are said to be private, which means that they cannot be referenced by name anyplace except within the definitions of the member functions of the class DayOfYear. For example, with this changed definition of the class DayOfYear, the following two assignments and other indicated code are no longer permitted in the main function of the program and are not permitted in any other function definition, except for member functions of the class DayOfYear: DayOfYear today; //This line is OK. today.month = 12;//ILLEGAL today.day = 25;//ILLEGAL cout << today.month;//ILLEGAL cout << today.day;//ILLEGAL if (today.month == 1) //ILLEGAL cout << "January"; Once you make a member variable a private member variable, there is no way to change its value (or to reference the member variable in any other way) except by using one of the member functions. That means that the compiler will enforce the hiding of encapsu- lation private: private member variable 06_CH06.fm Page 243 Wednesday, August 13, 2003 12:54 PM 244 Structures and Classes Display 6.4 Class with Private Members (part 1 of 3) 1 #include <iostream> 2 #include <cstdlib> 3 using namespace std; 4 class DayOfYear 5 { 6 public: 7 void input( ); 8 void output( ); 9 void set(int newMonth, int newDay); 10 //Precondition: newMonth and newDay form a possible date. 11 void set(int newMonth); 12 //Precondition: 1 <= newMonth <= 12 13 //Postcondition: The date is set to the first day of the given month. 14 int getMonthNumber( ); //Returns 1 for January, 2 for February, etc. 15 int getDay( ); 16 private: 17 int month; 18 int day; 19 }; 20 int main( ) 21 { 22 DayOfYear today, bachBirthday; 23 cout << "Enter today’s date:\n"; 24 today.input( ); 25 cout << "Today’s date is "; 26 today.output( ); 27 cout << endl; 28 bachBirthday.set(3, 21); 29 cout << "J. S. Bach’s birthday is "; 30 bachBirthday.output( ); 31 cout << endl; 32 if ( today.getMonthNumber( ) == bachBirthday.getMonthNumber( ) && 33 today.getDay( ) == bachBirthday.getDay( ) ) 34 cout << "Happy Birthday Johann Sebastian!\n"; 35 else 36 cout << "Happy Unbirthday Johann Sebastian!\n"; 37 38 return 0; 39 } 40 //Uses iostream and cstdlib: 41 void DayOfYear::set(int newMonth, int newDay) Private members This is an improved version of the class DayOfYear that we gave in Display 6.3. Note that the function name set is overloaded. You can overload a member function just like you can overload any other function. 06_CH06.fm Page 244 Wednesday, August 13, 2003 12:54 PM Classes 245 Display 6.4 Class with Private Members (part 2 of 3) 42 { 43 if ((newMonth >= 1) && (newMonth <= 12)) 44 month = newMonth; 45 else 46 { 47 cout << "Illegal month value! Program aborted.\n"; 48 exit(1); 49 } 50 if ((newDay >= 1) && (newDay <= 31)) 51 day = newDay; 52 else 53 { 54 cout << "Illegal day value! Program aborted.\n"; 55 exit(1); 56 } 57 } 58 //Uses iostream and cstdlib: 59 void DayOfYear::set(int newMonth) 60 { 61 if ((newMonth >= 1) && (newMonth <= 12)) 62 month = newMonth; 63 else 64 { 65 cout << "Illegal month value! Program aborted.\n"; 66 exit(1); 67 } 68 day = 1; 69 } 70 71 int DayOfYear::getMonthNumber( ) 72 { 73 return month; 74 } 75 int DayOfYear::getDay( ) 76 { 77 return day; 78 } 79 //Uses iostream and cstdlib: 80 void DayOfYear::input( ) 81 { 82 cout << "Enter the month as a number: "; 83 cin >> month; 84 cout << "Enter the day of the month: "; 85 cin >> day; Mutator functions Accessor functions Private members may be used in member function definitions (but not elsewhere). 06_CH06.fm Page 245 Wednesday, August 13, 2003 12:54 PM 246 Structures and Classes the implementation of the data for the class DayOfYear. If you look carefully at the pro- gram in Display 6.4, you will see that the only place the member variable names month and day are used is in the definitions of the member functions. There is no reference to today.month, today.day, bachBirthday.month, or bachBirthday.day anyplace outside the definitions of member functions. All the items that follow the word public: (in this case the member functions) are said to be public, which means that they can be referenced by name anyplace. There are no restrictions on the use of public members. Any member variables can be either public or private. Any member functions can be public or private. However, normal good programming practices require that all mem- ber variables be private and that typically most member functions be public. You can have any number of occurrences of public and private access specifiers in a class definition. Every time you insert the label public: the list of members changes from private to public. Every time you insert the label private: the list of members changes back to being private members. You need not have just one public and one private group of members. However, it is common to have just one public section and one private section. Display 6.4 Class with Private Members (part 3 of 3) 86 if ((month < 1) || (month > 12) || (day < 1) || (day > 31)) 87 { 88 cout << "Illegal date! Program aborted.\n"; 89 exit(1); 90 } 91 } 92 void DayOfYear::output( ) 93 < The rest of the definition of DayOfYear::output is given in Display 6.3. > S AMPLE D IALOGUE Enter today’s date: Enter the month as a number: 3 Enter the day of the month: 21 Today’s date is March 21 J. S. Bach’s birthday is March 21 Happy Birthday Johann Sebastian! public: public member variable 06_CH06.fm Page 246 Wednesday, August 13, 2003 12:54 PM Classes 247 There is no universal agreement about whether the public members should be listed first or the private members should be listed first. The majority seem to prefer listing the public members first. This allows for easy viewing of the portions programmers using the class actually get to use. You can make your own decision on what you wish to place first, but the examples in the book will go along with the majority and list the public members before the private members. In one sense C++ seems to favor placing the private members first. If the first group of members has neither the public: nor the private: specifier, then members of that group will automatically be private. You will see this default behavior used in code and should be familiar with it. However, we will not use it in this book. ■ ACCESSOR AND MUTATOR FUNCTIONS You should always make all member variables in a class private. You may sometimes need to do something with the data in a class object, however. The member functions will allow you to do many things with the data in an object, but sooner or later you will want or need to do something with the data for which there is no member function. How can you do anything new with the data in an object? The answer is that you can do anything you might reasonably want, provided you equip your classes with suitable accessor and mutator functions. These are member functions that allow you to access and change the data in an object in a very general way. Accessor functions allow you to read the data. In Display 6.4, the member functions getMonthNumber and getDay are accessor functions. The accessor functions need not literally return the values of each member variable, but they must return something equivalent to those values. For exam- ple, for a class like DayOfYear, you might have an accessor function return the name of the month as some sort of string value, rather than return the month as a number. Mutator functions allow you to change the data. In Display 6.4, the two functions named set are mutator functions. It is traditional to use names that include the word get for accessor functions and names that include the word set for mutator functions. (The functions input and output in Display 6.4 are really mutator and accessor func- tions, respectively, but I/O is such a special case that they are usually just called I/O functions rather than accessor or mutator functions.) Your class definitions should always provide an adequate collection of accessor and mutator functions. It may seem that accessor and mutator functions defeat the purpose of making mem- ber variables private, but that is not so. Notice the mutator function set in Display 6.4. It will not allow you to set the month member variable to 13 or to any number that does not represent a month. Similarly, it will not allow you to set the day member variable to any number that is not in the range 1 to 31 (inclusive). If the variables were public you could set the data to values that do not make sense for a date. (As it is, you can still set the data to values that do not represent a real date, such as February 31, but it would be easy to exclude these dates as well. We did not exclude these dates to keep the example simple.) With mutator functions, you can control and filter changes to the data. accessor function mutator function 06_CH06.fm Page 247 Wednesday, August 13, 2003 12:54 PM 248 Structures and Classes Tip Self-Test Exercises 12. Suppose your program contains the following class definition, class Automobile { public: void setPrice(double newPrice); void setProfit(double newProfit); double getPrice( ); private: double price; double profit; double getProfit( ); }; and suppose the main function of your program contains the following declaration and that the program somehow sets the values of all the member variables to some values: Automobile hyundai, jaguar; Which of the following statements are then allowed in the main function of your program? hyundai.price = 4999.99; jaguar.setPrice(30000.97); double aPrice, aProfit; aPrice = jaguar.getPrice( ); aProfit = jaguar.getProfit( ); aProfit = hyundai.getProfit( ); hyundai = jaguar; 13. Suppose you change Self-Test Exercise 12 so that in the definition of the class Automobile all member variables are public instead of private. How would this change your answer to the question in Self-Test Exercise 12? 14. Explain what public: and private: mean in a class definition. 15. a. How many public: sections are required in a class for the class to be useful? b. How many private: sections are required in a class? S EPARATE I NTERFACE AND I MPLEMENTATION The principle of encapsulation says that you should define classes so that a programmer who uses the class need not be concerned with the details of how the class is implemented. The programmer who uses the class need only know the rules for how to use the class. The rules for how to use the class are known as the ii ii nn nn tt tt ee ee rr rr ff ff aa aa cc cc ee ee or AA AA PP PP II II . There is some disagreement on exactly what the initials API stand for, but it is generally agreed that they stand for something like application programmer interface API 06_CH06.fm Page 248 Wednesday, August 13, 2003 12:54 PM Classes 249 Tip interface or abstract programming interface or something similar. In this book we will call these rules the interface for the class. It is important to keep in mind a clear distinction between the interface and the implementation of a class. If your class is well designed, then any programmer who uses the class need only know the interface for the class and need not know any details of the implementation of the class. A class whose interface and implementation are separated in this way is sometimes called an abstract data type (ADT) or a nicely encapsulated class. In Chapter 11 we will show you how to separate the interface and implementation by placing them in different files, but the important thing is to keep them conceptually separated. For a C++ class, the ii ii nn nn tt tt ee ee rr rr ff ff aa aa cc cc ee ee consists of two sorts of things: the comments, usually at the begin- ning of the class definition, that tell what the data of the object is supposed to represent, such as a date or bank account or state of a simulated car wash; and the public member functions of the class along with the comments that tell how to use these public member functions. In a well- designed class, the interface of the class should be all you need to know in order to use the class in your program. The ii ii mm mm pp pp ll ll ee ee mm mm ee ee nn nn tt tt aa aa tt tt ii ii oo oo nn nn of a class tells how the class interface is realized as C++ code. The implemen- tation consists of the private members of the class and the definitions of both the public and pri- vate member functions. Although you need the implementation in order to run a program that uses the class, you should not need to know anything about the implementation in order to write the rest of a program that uses the class; that is, you should not need to know anything about the implementation in order to write the main function of the program and to write any nonmember functions or other classes used by the main function. The most obvious benefit you derive from cleanly separating the interface and implementation of your classes is that you can change the implementation without having to change the other parts of your program. On large programming projects this division between interface and implemen- tation will facilitate dividing the work among different programmers. If you have a well-designed interface, then one programmer can write the implementation for the class while other program- mers write the code that uses the class. Even if you are the only programmer working on a project, you have divided one larger task into two smaller tasks, which makes your program easier to design and to debug. A T EST FOR E NCAPSULATION If your class definition produces an ADT (that is, if it properly separates the interface and the implementation), then you can change the implementation of the class (that is, change the data representation and/or change the implementation of some member functions) without needing to change any (other) code for any program that uses the class definition. This is a sure test for whether you have defined an ADT or just some class that is not properly encapsulated. For example, you can change the implementation of the class DayOfYear in Display 6.4 to the following and no program that uses this class definition would need any changes: class DayOfYear { implemen- tation 06_CH06.fm Page 249 Wednesday, August 13, 2003 12:54 PM 250 Structures and Classes public: void input( ); void output( ); void set(int newMonth, int newDay); //Precondition: newMonth and newDay form a possible date. //Postcondition: The date is reset according to the arguments. void set(int newMonth); //Precondition: 1 <= newMonth <= 12 //Postcondition: The date is set to first day of the month. int getMonthNumber( ); //Returns 1 for January, 2 for February, etc. int getDay( ); private: char firstLetter;//of month char secondLetter;//of month char thirdLetter;//of month int day; }; In this version, a month is represented by the first three letters in its name, such as ’J’, ’a’, and ’n’ for January. The member functions should also be rewritten, of course, but they can be rewritten to behave exactly as they did before. For example, the definition of the function get- MonthNumber might start as follows: int DayOfYear::getMonthNumber( ) { if (firstLetter == ’J’ && secondLetter == ’a’ && thirdLetter == ’n’) return 1; if (firstLetter == ’F’ && secondLetter == ’e’ && thirdLetter == ’b’) return 2; . . . This would be rather tedious, but not difficult. ■ STRUCTURES VERSUS CLASSES Structures are normally used with all member variables public and with no member functions. However, in C++ a structure can have private member variables and both public and private member functions. Aside from some notational differences, a C++ structure can do anything a class can do. Having said this and satisfied the “truth in adver- tising” requirement, we advocate that you forget this technical detail about structures. If 06_CH06.fm Page 250 Wednesday, August 13, 2003 12:54 PM Classes 251 C LASSES AND O BJECTS A class is a type whose variables can have both member variables and member functions. The syntax for a class definition is given below. S YNTAX class Class_Name { . public: Member_SpecificationN+1 Member_SpecificationN+2 . . . private: Member_Specification_1 Member_Specification_2 . . . Member_SpecificationN }; Each Member_Specification_i is either a member variable declaration or a member function declaration (prototype). Additional public: and private: sections are permitted. If the first group of members does not have either a public: or a private: label, then it is the same as if there were a private: before the first group. E XAMPLE class Bicycle { public: char getColor( ); int numberOfSpeeds( ); void set(int theSpeeds, char theColor); private: int speeds; char color; }; Once a class is defined, an object variable (variable of the class type) can be declared in the same way as variables of any other type. For example, the following declares two object variables of type Bicycle: Bicycle myBike, yourBike; Public members Private members Do not forget this semicolon. 06_CH06.fm Page 251 Wednesday, August 13, 2003 12:54 PM 252 Structures and Classes Self-Test Exercises Tip you take this technical detail seriously and use structures in the same way that you use classes, then you will have two names (with different syntax rules) for the same con- cept. On the other hand, if you use structures as we described them, then you will have a meaningful difference between structures (as you use them) and classes; and your usage will be the same as that of most other programmers. One difference between a structure and a class is that they differ in how they treat an initial group of members that has neither a public nor a private access specifier. If the first group of members in a definition is not labeled with either public: or private:, then a structure assumes the group is public, whereas a class would assume the group is private. T HINKING O BJECTS If you have not programmed with classes before, it can take a little while to get the feel of pro- gramming with them. When you program with classes, data rather than algorithms takes center stage. It is not that there are no algorithms. However, the algorithms are made to fit the data, as opposed to designing the data to fit the algorithms. It’s a difference in point of view. In the extreme case, which is considered by many to be the best style, you have no global functions at all, only classes with member functions. In this case, you define objects and how the objects inter- act, rather than algorithms that operate on data. We will discuss the details of how you accom- plish this throughout this book. Of course, you can ignore classes completely or relegate them to a minor role, but then you are really programming in C, not C++. 16. When you define a C++ class, should you make the member variables public or private? Should you make the member functions public or private? 17. When you define a C++ class, what items are considered part of the interface? What items are considered part of the implementation? ■ A structure can be used to combine data of different types into a single (compound) data value. ■ A class can be used to combine data and functions into a single (compound) object. ■ A member variable or a member function for a class can be either public or private. If it is public, it can be used outside the class. If it is private, it can be used only in the definition of a member function. Chapter Summary 06_CH06.fm Page 252 Wednesday, August 13, 2003 12:54 PM . in C, not C++. 16. When you define a C++ class, should you make the member variables public or private? Should you make the member functions public or private? 17. When you define a C++ class,. that you forget this technical detail about structures. If 06_CH06.fm Page 250 Wednesday, August 13, 2003 12:54 PM Classes 251 C LASSES AND O BJECTS A class is a type whose variables can have. yourBike; Public members Private members Do not forget this semicolon. 06_CH06.fm Page 251 Wednesday, August 13, 2003 12:54 PM 252 Structures and Classes Self-Test Exercises Tip you take this technical detail

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

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan