Constructors 273 Display 7.2 Bank Account Class (part 5 of 5) 161 return static_cast<int>(amount); 162 } 163 //Uses cmath: 164 int BankAccount::centsPart(double amount) 165 { 166 double doubleCents = amount*100; 167 int intCents = (round(fabs(doubleCents)))%100;//% can misbehave on negatives 168 if (amount < 0) 169 intCents = -intCents; 170 return intCents; 171 } 172 //Uses cmath: 173 int BankAccount::round(double number) 174 { 175 return static_cast<int>(floor(number + 0.5)); 176 } 177 double BankAccount::fraction(double percent) 178 { 179 return (percent/100.0); 180 } S AMPLE D IALOGUE account1 initialized as follows: Account balance: $1345.52 Rate: 2.3% account2 initialized as follows: Account balance: $0.00 Rate: 0% account1 reset to the following: Account balance: $999.99 Rate: 5.5% Enter new data for account 2: Enter account balance $100.00 Enter interest rate (NO percent sign): 10 account2 reset to the following: Account balance: $100 Rate: 10% In one year account2 will grow to: Account balance: $110 Rate: 10% if this does not seem clear, see the discussion of round in Chapter 3, Section 3.2. These could be regular functions rather than member functions, but as member functions we were able to make them private. 07_CH07.fm Page 273 Wednesday, August 13, 2003 12:58 PM 274 Constructors and Other Tools Self-Test Exercises 3. The function BankAccount::input in Display 7.2 reads the balance of the account as a value of type double. When the value is stored in the computer’s memory in binary form, this can create a slight error. It would normally not be noticed and the function is good enough for the demonstration class BankAccount. Spending too much time on numerical analysis would detract from the message at hand. Still, this input function is not good enough for banking. Rewrite the function BankAccount::input so it reads an amount such as 78.96 as the int 76 and the three char values ’.’, ’9’, and ’6’. You can assume the user always enters two digits for the cents in an amount, such as 99.00 instead of just 99 and nothing more. Hint: The following formula will convert a digit to the correspond- ing int value, such as ’6’ to 6: static_cast<int>(digit) - static_cast<int>(’0’) ■ CLASS TYPE MEMBER VARIABLES A class may have a member variable whose type is that of another class. By and large there is nothing special that you need to do to have a class member variable, but there is a special notation to allow for the invocation of the member variable’s constructor within the constructor of the outer class. An example is given in Display 7.3. The class Holiday in Display 7.3 might be used by some city police department to help keep track of which holidays will have parking enforcement (of things such as parking meters and one hour parking zones). It’s a highly simplified class. A real class would have more member functions, but the class Holiday is complete enough to illus- trate our points. The class Holiday has two member variables. The member variable parkingEn- forcement is an ordinary member variable of the simple type bool. The member vari- able date is of the class type DayOfYear. Below we have reproduced one constructor definition from Display 7.3: Holiday::Holiday(int month, int day, bool theEnforcement) : date(month, day), parkingEnforcement(theEnforcement) {/*Intentionally empty*/} Notice that we have set the member variable parkingEnforcement in the initialization section in the usual way, namely, with parkingEnforcement(theEnforcement) The member variable date is a member of the class type DayOfYear. To initialize date, we need to invoke a constructor from the class DayOfYear (the type of date). This is done in the initialization section with the similar notation date(month, day) 07_CH07.fm Page 274 Wednesday, August 13, 2003 12:58 PM Constructors 275 Display 7.3 A Class Member Variable (part 1 of 3) 1 #include <iostream> 2 #include<cstdlib> 3 using namespace std; 4 class DayOfYear 5 { 6 public: 7 DayOfYear(int monthValue, int dayValue); 8 DayOfYear(int monthValue); 9 DayOfYear( ); 10 void input( ); 11 void output( ); 12 int getMonthNumber( ); 13 int getDay( ); 14 private: 15 int month; 16 int day; 17 void testDate( ); 18 }; 19 class Holiday 20 { 21 public: 22 Holiday( );//Initializes to January 1 with no parking enforcement 23 Holiday(int month, int day, bool theEnforcement); 24 void output( ); 25 private: 26 DayOfYear date; 27 bool parkingEnforcement;//true if enforced 28 }; 29 int main( ) 30 { 31 Holiday h(2, 14, true); 32 cout << "Testing the class Holiday.\n"; 33 h.output( ); 34 return 0; 35 } 36 37 Holiday::Holiday( ) : date(1, 1), parkingEnforcement(false) 38 {/*Intentionally empty*/} 39 Holiday::Holiday(int month, int day, bool theEnforcement) 40 : date(month, day), parkingEnforcement(theEnforcement) 41 {/*Intentionally empty*/} member variable of a class type The class DayOfYear is the same as in Display 7.1, but we have repeated all the details you need for this discussion. Invocations of constructors from the class DayOfYear. 07_CH07.fm Page 275 Wednesday, August 13, 2003 12:58 PM 276 Constructors and Other Tools Display 7.3 A Class Member Variable (part 2 of 3) 42 void Holiday::output( ) 43 { 44 date.output( ); 45 cout << endl; 46 if (parkingEnforcement) 47 cout << "Parking laws will be enforced.\n"; 48 else 49 cout << "Parking laws will not be enforced.\n"; 50 } 51 DayOfYear::DayOfYear(int monthValue, int dayValue) 52 : month(monthValue), day(dayValue) 53 { 54 testDate( ); 55 } 56 //uses iostream and cstdlib: 57 void DayOfYear::testDate( ) 58 { 59 if ((month < 1) || (month > 12)) 60 { 61 cout << "Illegal month value!\n"; 62 exit(1); 63 } 64 if ((day < 1) || (day > 31)) 65 { 66 cout << "Illegal day value!\n"; 67 exit(1); 68 } 69 } 70 71 //Uses iostream: 72 void DayOfYear::output( ) 73 { 74 switch (month) 75 { 76 case 1: 77 cout << "January "; break; 78 case 2: 79 cout << "February "; break; 80 case 3: 81 cout << "March "; break; . . . The omitted lines are in Display 6.3, but they are obvious enough that you should not have to look there. 07_CH07.fm Page 276 Wednesday, August 13, 2003 12:58 PM More Tools 277 The notation date(month, day) is an invocation of the constructor for the class DayOf- Year with arguments month and day to initialize the member variables of date. Notice that this notation is analogous to how you would declare a variable date of type Day- OfYear . Also notice that the parameters of the larger class constructor Holiday can be used in the invocation of the constructor for the member variable. More Tools Intelligence . . . is the facility of making artificial objects, especially tools to make tools. Henri Bergson, Creative Evolution This section discusses three topics that, although important, did not fit easily before here. The three topics are const parameters for classes, inline functions, and static class members. ■ THE const PARAMETER MODIFIER A call-by-reference parameter is more efficient than a call-by-value parameter. A call- by-value parameter is a local variable that is initialized to the value of its argument, so when the function is called there are two copies of the argument. With a call-by-reference parameter, the parameter is just a placeholder that is replaced by the argument, so there is only one copy of the argument. For parameters of simple types, such as int or dou- ble , the difference in efficiency is negligible, but for class parameters the difference in Display 7.3 A Class Member Variable (part 3 of 3) 82 case 11: 83 cout << "November "; break; 84 case 12: 85 cout << "December "; break; 86 default: 87 cout << "Error in DayOfYear::output. Contact software vendor."; 88 } 89 cout << day; 90 } S AMPLE D IALOGUE Testing the class Holiday. February 14 Parking laws will be enforced. 7.2 07_CH07.fm Page 277 Wednesday, August 13, 2003 12:58 PM 278 Constructors and Other Tools efficiency can sometimes be important. Thus, it can make sense to use a call-by-reference parameter rather than a call-by-value parameter for a class, even if the function does not change the parameter. If you are using a call-by-reference parameter and your function does not change the value of the parameter, you can mark the parameter so that the compiler knows that the parameter should not be changed. To do so, place the modifier const before the parameter type. The parameter is then called a constant parameter or constant call- by-reference parameter. For example, in Display 7.2 we defined a class named BankAccount for simple bank accounts. In some program you might want to write a Boolean-valued function to test which of two accounts has the larger balance. The def- inition of the function might be as follows: bool isLarger(BankAccount account1, BankAccount account2) //Returns true if the balance in account1 is greater than that //in account2. Otherwise returns false. { return(account1.getBalance( ) > account2.getBalance( )); } This is perfectly legal. The two parameters are call-by-value parameters. However, it would be more efficient and is more common to make the parameters constant call-by- reference parameters, as follows: bool isLarger(const BankAccount& account1, const BankAccount& account2) //Returns true if the balance in account1 is greater than that //in account2. Otherwise, returns false. { return(account1.getBalance( ) > account2.getBalance( )); } Note that the only difference is that we made the parameter call-by-reference by adding & and we added the const modifiers. If there is a function declaration, then the same change must be made to the parameters in the function declaration. Constant parameters are a form of automatic error checking. If your function defini- tion contains a mistake that causes an inadvertent change to the constant parameter, the compiler will issue an error message. The parameter modifier const can be used with any kind of parameter; however, it is normally used only for call-by-reference parameters for classes (and for certain other parameters whose corresponding arguments are large, such as arrays). Suppose you invoke a member function for an object of a class, such as the class BankAccount in Display 7.2. For example: BankAccount myAccount; myAccount.input( ); myAccount.output( ); constant parameter 07_CH07.fm Page 278 Wednesday, August 13, 2003 12:58 PM More Tools 279 Pitfall The invocation of the member function input changes the values of the member vari- ables in the calling object myAccount. So the calling object behaves sort of like a call-by- reference parameter; the function invocation can change the calling object. Sometimes, you do not want to change the member variables of the calling object. For example, the member function output should not change the values of the calling object’s member variables. You can use the const modifier to tell the compiler that a member function invocation should not change the calling object. The modifier const applies to calling objects in the same way that it applies to parameters. If you have a member function that should not change the value of a call- ing object, you can mark the function with the const modifier; the computer will then issue an error message if your function code inadvertently changes the value of the call- ing object. In the case of a member function, the const goes at the end of the function declaration, just before the final semicolon, as shown below: class BankAccount { public: void output( ) const; The modifier const should be used in both the function declaration and the function definition, so the function definition for output would begin as follows: void BankAccount::output( ) const { The remainder of the function definition would be the same as in Display 7.2. I NCONSISTENT U SE OF const Use of the const modifier is an all-or-nothing proposition. If you use const for one parameter of a particular type, then you should use it for every other parameter that has that type and that is not changed by the function call. Moreover, if the type is a class type, then you should also use the const modifier for every member function that does not change the value of its calling object. The reason has to do with function calls within function calls. For example, consider the following definition of the function welcome: void welcome(const BankAccount& yourAccount) { cout << "Welcome to our bank.\n" << "The status of your account is:\n"; yourAccount.output( ); } const with member functions 07_CH07.fm Page 279 Wednesday, August 13, 2003 12:58 PM 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 . 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. 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. Constructors 273 Display 7.2 Bank Account Class (part 5 of 5) 161 return static_cast<int>(amount); 162 } 163 //Uses cmath: 164 int BankAccount::centsPart(double amount) 165 { 166 double doubleCents