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
477,52 KB
Nội dung
280 Constructors and Other Tools If you do not add the const modifier to the function declaration for the member function out- put , then the function welcome will produce an error message. The member function welcome does not change the calling object price. However, when the compiler processes the function definition for welcome, it will think that welcome does (or at least might) change the value of const P ARAMETER M ODIFIER If you place the modifier const before the type for a call-by-reference parameter, the parameter is called a cc cc oo oo nn nn ss ss tt tt aa aa nn nn tt tt pp pp aa aa rr rr aa aa mm mm ee ee tt tt ee ee rr rr . When you add the const you are telling the compiler that this parameter should not be changed. If you make a mistake in your definition of the function so that it does change the constant parameter, then the compiler will give an error message. Parameters of a class type that are not changed by the function ordinarily should be constant call-by-reference parameters rather than call-by-value parameters. If a member function does not change the value of its calling object, then you can mark the func- tion by adding the const modifier to the function declaration. If you make a mistake in your def- inition of the function so that it does change the calling object and the function is marked with const, the computer will give an error message. The const is placed at the end of the function declaration, just before the final semicolon. The heading of the function definition should also have a const so that it matches the function declaration. E XAMPLE class Sample { public: Sample( ); void input( ); void output( ) const; private: int stuff; double moreStuff; }; int compare(const Sample& s1, const Sample& s2); Use of the const modifier is an all or nothing proposition. You should use the const modifier whenever it is appropriate for a class parameter and whenever it is appropriate for a member function of the class. If you do not use const every time that it is appropriate for a class, then you should never use it for that class. 07_CH07.fm Page 280 Wednesday, August 13, 2003 12:58 PM More Tools 281 Self-Test Exercises yourAccount. This is because when it is translating the function definition for welcome, all that the compiler knows about the member function output is the function declaration for output. If the function declaration does not contain a const that tells the compiler that the calling object will not be changed, then the compiler assumes that the calling object will be changed. Thus, if you use the modifier const with parameters of type BankAccount, then you should also use const with all BankAccount member functions that do not change the values of their calling objects. In particular, the function declaration for the member function output should include a const. In Display 7.4 we have rewritten the definition of the class BankAccount given in Display 7.2, but this time we have used the const modifier where appropriate. In Display 7.4 we have also added the two functions isLarger and welcome, which we discussed earlier and which have constant parameters. 4. Why would it be incorrect to add the modifier const, as shown below, to the declaration for the member function input of the class BankAccount given in Display 7.2? class BankAccount { public: void input( ) const; 5. What are the differences and the similarities between a call-by-value parameter and a con- stant call-by-reference parameter? Declarations that illustrate these follow. void callByValue(int x); void callByConstReference(const int& x); 6. Given the definitions const int x = 17; class A { public: A( ); A(int n); int f( )const; int g(const A& x); private: int i; }; Each of the three const keywords is a promise to the compiler that the compiler will enforce. What is the promise in each case? 07_CH07.fm Page 281 Wednesday, August 13, 2003 12:58 PM 282 Constructors and Other Tools Display 7.4 The const Parameter Modifier (part 1 of 3) 1 #include <iostream> 2 #include <cmath> 3 #include <cstdlib> 4 using namespace std; 5 //Data consists of two items: an amount of money for the account balance 6 //and a percentage for the interest rate. 7 class BankAccount 8 { 9 public: 10 BankAccount(double balance, double rate); 11 //Initializes balance and rate according to arguments. 12 BankAccount(int dollars, int cents, double rate); 13 //Initializes the account balance to $dollars.cents. For a negative balance both 14 //dollars and cents must be negative. Initializes the interest rate to rate percent. 15 BankAccount(int dollars, double rate); 16 //Initializes the account balance to $dollars.00 and 17 //initializes the interest rate to rate percent. 18 BankAccount( ); 19 //Initializes the account balance to $0.00 and the interest rate to 0.0%. 20 void update( ); 21 //Postcondition: One year of simple interest has been added to the account. 22 void input( ); 23 void output( ) const; 24 double getBalance( ) const; 25 int getDollars( ) const; 26 int getCents( ) const; 27 double getRate( ) const;//Returns interest rate as a percentage. 28 void setBalance(double balance); 29 void setBalance(int dollars, int cents); 30 //Checks that arguments are both nonnegative or both nonpositive. 31 void setRate(double newRate); 32 //If newRate is nonnegative, it becomes the new rate. Otherwise, abort program. 33 34 private: 35 //A negative amount is represented as negative dollars and negative cents. 36 //For example, negative $4.50 sets accountDollars to -4 and accountCents to -50. 37 int accountDollars; //of balance 38 int accountCents; //of balance 39 double rate;//as a percent This is class from Display 7.2 rewritten using the const modifier. 07_CH07.fm Page 282 Wednesday, August 13, 2003 12:58 PM More Tools 283 Display 7.4 The const Parameter Modifier (part 2 of 3) 40 int dollarsPart(double amount) const; 41 int centsPart(double amount) const; 42 int round(double number) const; 43 double fraction(double percent) const; 44 //Converts a percentage to a fraction. For example, fraction(50.3) returns 0.503. 45 }; 46 //Returns true if the balance in account1 is greater than that 47 //in account2. Otherwise returns false. 48 bool isLarger(const BankAccount& account1, const BankAccount& account2); 49 void welcome(const BankAccount& yourAccount); 50 int main( ) 51 { 52 BankAccount account1(6543.21, 4.5), account2; 53 welcome(account1); 54 cout << "Enter data for account 2:\n"; 55 account2.input( ); 56 if (isLarger(account1, account2)) 57 cout << "account1 is larger.\n"; 58 else 59 cout << "account2 is at least as large as account1.\n"; 60 return 0; 61 } 62 63 bool isLarger(const BankAccount& account1, const BankAccount& account2) 64 { 65 return(account1.getBalance( ) > account2.getBalance( )); 66 } 67 void welcome(const BankAccount& yourAccount) 68 { 69 cout << "Welcome to our bank.\n" 70 << "The status of your account is:\n"; 71 yourAccount.output( ); 72 } 73 //Uses iostream and cstdlib: 74 void BankAccount::output( ) const 75 < The rest of the function definition is the same as in Display 7.2. > 76 < Other function definitions are the same as in Display 7.2, except that 77 const is added where needed to match the function declaration. > 07_CH07.fm Page 283 Wednesday, August 13, 2003 12:58 PM 284 Constructors and Other Tools Self-Test Exercises ■ INLINE FUNCTIONS You can give the complete definition of a member function within the definition of its class. Such definitions are called inline function definitions. These inline definitions are typically used for very short function definitions. Display 7.5 shows the class in Display 7.4 rewritten with a number of inline functions. Inline functions are more than just a notational variant of the kind of member func- tion definitions we have already seen. The compiler treats an inline function in a special way. The code for an inline function declaration is inserted at each location where the function is invoked. This saves the overhead of a function invocation. All other things being equal, an inline function should be more efficient and hence presumably preferable to a function defined in the usual way. However, all other things are seldom, if ever, equal. Inline functions have the disadvantage of mixing the interface and implementation of a class and so go against the principle of encapsulation. And, so the usual arguments go back and forth. It is generally believed that only very short function definitions should be defined inline. For long function definitions, the inline version can actually be less efficient, because a large piece of code is repeated frequently. Beyond that general rule, you will have to decide for yourself whether to use inline functions. Any function can be defined to be an inline function. To define a nonmember func- tion to be inline, just place the keyword inline before the function declaration and function definition. We will not use, or further discuss, inline nonmember functions in this book. 7. Rewrite the definition of the class DayOfYear given in Display 7.3 so that the functions getMonthNumber and getDay are defined inline. Display 7.4 The const Parameter Modifier (part 3 of 3) S AMPLE D IALOGUE Welcome to our bank. The status of your account is: Account balance: $6543.21 Rate: 4.5% Enter data for account 2: Enter account balance $100.00 Enter interest rate (NO percent sign): 10 account1 is larger. inline function 07_CH07.fm Page 284 Wednesday, August 13, 2003 12:58 PM More Tools 285 Display 7.5 Inline Function Definitions 1 #include <iostream> 2 #include <cmath> 3 #include <cstdlib> 4 using namespace std; 5 class BankAccount 6 { 7 public: 8 BankAccount(double balance, double rate); 9 BankAccount(int dollars, int cents, double rate); 10 BankAccount(int dollars, double rate); 11 BankAccount( ); 12 void update( ); 13 void input( ); 14 void output( ) const; 15 double getBalance( ) const { return (accountDollars + accountCents*0.01);} 16 int getDollars( ) const { return accountDollars; } 17 int getCents( ) const { return accountCents; } 18 double getRate( ) const { return rate; } 19 void setBalance(double balance); 20 void setBalance(int dollars, int cents); 21 void setRate(double newRate); 22 private: 23 int accountDollars; //of balance 24 int accountCents; //of balance 25 double rate;//as a percentage 26 int dollarsPart(double amount) const { return static_cast<int>(amount); } 27 int centsPart(double amount) const; 28 int round(double number) const 29 { return static_cast<int>(floor(number + 0.5)); } 30 double fraction(double percent) const { return (percent/100.0); } 31 }; < Inline functions have no further definitions. Other function definitions are as in Display 7.4. > This is Display 7.4 rewritten using inline member functions. 07_CH07.fm Page 285 Wednesday, August 13, 2003 12:58 PM 286 Constructors and Other Tools ■ STATIC MEMBERS Sometimes you want to have one variable that is shared by all the objects of a class. For example, you might want one variable to count the number of times a particular mem- ber function is invoked by all objects of the class. Such variables are called static vari- ables and can be used for objects of the class to communicate with each other or coordinate their actions. Such variables allow some of the advantages of global variables without opening the flood gates to all the abuses that true global variables invite. In particular, a static variable can be private so that only objects of the class can directly access it. If a function does not access the data of any object and yet you want the function to be a member of the class, you can make it a static function. Static functions can be invoked in the normal way, using a calling object of the class. However, it is more com- mon and clearer to invoke a static function using the class name and scope resolution operator, as in the following example: Server::getTurn( ) Because a static function does not need a calling object, the definition of a static function cannot use anything that depends on a calling object. A static function defini- tion cannot use any nonstatic variables or nonstatic member functions, unless the non- static variable or function has a calling object that is a local variable or some object otherwise created in the definition. If that last sentence seems hard to understand, just use the simpler rule that the definition of a static function cannot use anything that depends on a calling object. Display 7.6 is a demonstration program that uses both static variables and static functions. Note that static variables are indicated by the qualifying keyword static at the start of their declaration. Also notice that all the static variables are initialized as follows: int Server::turn = 0; int Server::lastServed = 0; bool Server::nowOpen = true; Such initialization requires a bit of explanation. Every static variable must be initialized outside the class definition. Also, a static variable cannot be initialized more than once. As in Display 7.6, private static variables—in fact, all static variables—are initialized outside the class. This may seem to be contrary to the notion of private. However, the author of a class is expected to do the initializations, typically in the same file as the class definition. In that case, no programmer who uses the class can initialize the static variables, since a static variable cannot be initialized a second time. Notice that the keyword static is used in the member function declaration but is not used in the member function definition. static variable initializing static member variables 07_CH07.fm Page 286 Wednesday, August 13, 2003 12:58 PM More Tools 287 Display 7.6 Static Members (part 1 of 2) 1 #include <iostream> 2 using namespace std; 3 class Server 4 { 5 public: 6 Server(char letterName); 7 static int getTurn( ); 8 void serveOne( ); 9 static bool stillOpen( ); 10 private: 11 static int turn; 12 static int lastServed; 13 static bool nowOpen; 14 char name; 15 }; 16 int Server:: turn = 0; 17 int Server:: lastServed = 0; 18 bool Server::nowOpen = true; 19 int main( ) 20 { 21 Server s1(’A’), s2(’B’); 22 int number, count; 23 do 24 { 25 cout << "How many in your group? "; 26 cin >> number; 27 cout << "Your turns are: "; 28 for (count = 0; count < number; count++) 29 cout << Server::getTurn( ) << ' '; 30 cout << endl; 31 s1.serveOne( ); 32 s2.serveOne( ); 33 } while (Server::stillOpen( )); 34 cout << "Now closing service.\n"; 35 return 0; 36 } 37 38 Server::Server(char letterName) : name(letterName) 39 {/*Intentionally empty*/} 40 int Server::getTurn( ) 41 { 42 turn++; 43 return turn; 44 } Since getTurn is static, only static members can be referenced in here. 07_CH07.fm Page 287 Wednesday, August 13, 2003 12:58 PM 288 Constructors and Other Tools The program in Display 7.6 is the outline of a scenario that has one queue of clients waiting for service and two servers to service this single queue. You can come up with a number of system programming scenarios to flesh this out to a realistic example. For a simple minded model just to learn the concepts, think of the numbers produced by getTurn as those little slips of paper handed out to customers in a delicatessen or ice cream shop. The two servers are then two clerks who wait on customers. One perhaps peculiar detail of this shop is that customers arrive in groups but are waited on one at a time (perhaps to order their own particular kind of sandwich or ice cream flavor). Display 7.6 Static Members (part 2 of 2) 45 bool Server::stillOpen( ) 46 { 47 return nowOpen; 48 } 49 void Server::serveOne( ) 50 { 51 if (nowOpen && lastServed < turn) 52 { 53 lastServed++; 54 cout << "Server " << name 55 << " now serving " << lastServed << endl; 56 } 57 if (lastServed >= turn) //Everyone served 58 nowOpen = false; 59 } S AMPLE D IALOGUE How many in your group? 3 Your turns are: 1 2 3 Server A now serving 1 Server B now serving 2 How many in your group? 2 Your turns are: 4 5 Server A now serving 3 Server B now serving 4 How many in your group? 0 Your turns are: Server A now serving 5 Now closing service. 07_CH07.fm Page 288 Wednesday, August 13, 2003 12:58 PM More Tools 289 Self-Test Exercises 8. Could the function defined as follows be added to the class Server in Display 7.6 as a static function? Explain your answer. void Server::showStatus( ) { cout << "Currently serving " << turn << endl; cout << "server name " << name << endl; } ■ NESTED AND LOCAL CLASS DEFINITIONS The material in this section is included for reference value and, except for a brief pass- ing reference in Chapter 17, is not used elsewhere in this book. You can define a class within a class. Such a class within a class is called a nested class. The general layout is obvious: class OuterClass { public: private: class InnerClass { }; }; A nested class can be either public or private. If it is private, as in our sample layout, then it cannot be used outside of the outer class. Whether the nested class is public or private, it can be used in member function definitions of the outer class. Since the nested class is in the scope of the outer class, the name of the nested class, like InnerClass in our sample layout, may be used for something else outside of the outer class. If the nested class is public, the nested class can be used as a type outside of the outer class. However, outside of the outer class, the type name of the nested class is OuterClass::InnerClass. We will not have occasion to use such nested class definitions in this book. However, in Chapter 17 we do suggest one possible application for nested classes. 2 A class definition can also be defined within a function definition. In such cases the class is called a local class, since its meaning is confined to the function definition. A 2 The suggestion is in the subsection of Chapter 17 entitled “Friend Classes and Similar Alter- natives.” nested class local class 07_CH07.fm Page 289 Wednesday, August 13, 2003 12:58 PM [...]... people are very comfortable with the usual operator syntax, x + 7, that C++ uses for types such as int and double And one way to view a high-level language, such as C++, is as a way to make people comfortable with programming computers Thus, this syntactic sugar is probably a good idea; at the least, it is a well-entrenched idea In C++ you can overload the operators, such as + and ==, so that they work... initialized with the default constructor is as follows: YourClass yetAnotherObject; 2 A default constructor is a constructor that takes no arguments Not every class has a default constructor If you define absolutely no constructors for a class, then a default constructor will be automatically provided On the other hand, if you define one or more constructors but do not define a default constructor, then... so either way I’ll get into the garden.” Lewis Carroll, Alice’s Adventures in Wonderland vector Vectors can be thought of as arrays that can grow (and shrink) in length while your program is running In C++, once your program creates an array, it cannot change the length of the array Vectors serve the same purpose as arrays except that they can change length while the program is running Vectors are formed... definition of the class Money is as shown in Display 8.1, so that the plus operator returns its value by const value? s OVERLOADING UNARY OPERATORS In addition to the binary operators, such as + in x + y, C++ has unary operators, such as the operator - when it is used to mean negation A unary operator is an operator that takes only one operand (one argument) In the statement below, the unary operator - . be thought of as arrays that can grow (and shrink) in length while your program is running. In C++, once your program creates an array, it cannot change the length of the array. Vectors serve. constructor that takes no arguments. Not every class has a default constructor. If you define absolutely no constructors for a class, then a default constructor will be automatically provided.