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

10 381 1
Absolute C++ (4th Edition) part 27 docx

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

Thông tin tài liệu

Constructors 263 Pitfall member function set (which we included in the old version of the class shown in Display 6.4). C ONSTRUCTORS WITH N O A RGUMENTS It is important to remember not to use any parentheses when you declare a class variable and want the constructor invoked with no arguments. For example, consider the following line from Display 7.1: DayOfYear date1(2, 21), date2(5), date3; Display 7.1 Class with Constructors (part 2 of 2) 41 DayOfYear::DayOfYear(int monthValue) : month(monthValue), day(1) 42 { 43 testDate( ); 44 } 45 DayOfYear::DayOfYear( ) : month(1), day(1) 46 {/*Body intentionally empty.*/} 47 //uses iostream and cstdlib: 48 void DayOfYear::testDate( ) 49 { 50 if ((month < 1) || (month > 12)) 51 { 52 cout << "Illegal month value!\n"; 53 exit(1); 54 } 55 if ((day < 1) || (day > 31)) 56 { 57 cout << "Illegal day value!\n"; 58 exit(1); 59 } 60 } S AMPLE D IALOGUE Initialized dates: February 21 May 1 January 1 date1 reset to the following: October 31 < Definitions of the other member functions are the same as in Display 6.4. > 07_CH07.fm Page 263 Wednesday, August 13, 2003 12:58 PM 264 Constructors and Other Tools The object date1 is initialized by the constructor that takes two arguments, the object date2 is initialized by the constructor that takes one argument, and the object date3 is initialized by the constructor that takes no arguments. It is tempting to think that empty parentheses should be used when declaring a variable for which you want the constructor with no arguments invoked, but there is a reason why this is not done. Consider the following, which seems like it should declare the variable date3 and invoke the con- structor with no arguments: DayOfYear date3( );//PROBLEM! Not what you might think it is. The problem with this is that although you may mean it as a declaration and constructor invoca- tion, the compiler sees it as a declaration (prototype) of a function named date3 that has no parameters and that returns a value of type DayOfYear. Since a function named date3 that has no parameters and that returns a value of type DayOfYear is perfectly legal, this notation always has that meaning. A different notation (without parentheses) is used when you want to invoke a constructor with no arguments. C ALLING A C ONSTRUCTOR A constructor is called automatically when an object is declared, but you must give the argu- ments for the constructor when you declare the object. A constructor can also be called explicitly, but the syntax is different from what is used for ordinary member functions. S YNTAX FOR AN O BJECT D ECLARATION W HEN Y OU H AVE C ONSTRUCTORS Class_Name Variable_Name(Arguments_for_Constructor); E XAMPLE DayOfYear holiday(7, 4); S YNTAX FOR AN E XPLICIT C ONSTRUCTOR C ALL Variable = Constructor_Name ( Arguments_For_Constructor ); E XAMPLE holiday = DayOfyear(10, 31); A constructor must have the same name as the class of which it is a member. Thus, in the above syntax descriptions, Class_Name and Constructor_Name are the same identifier. 07_CH07.fm Page 264 Wednesday, August 13, 2003 12:58 PM Constructors 265 Tip ■ EXPLICIT CONSTRUCTOR CALLS A constructor is called automatically whenever you declare an object of the class type, but it can also be called again after the object has been declared. This allows you to con- veniently set all the members of an object. The technical details are as follows. Calling the constructor creates an anonymous object with new values. An anonymous object is an object that is not named (as yet) by any variable. The anonymous object can be assigned to the named object. For example, the following is a call to the constructor DayOfYear that creates an anonymous object for the date May 5. This anonymous object is assigned to the variable holiday (which has been declared to be of type DayOf- Year ) so that holiday also represents the date May 5. 1 holiday = DayOfYear(5, 5); (As you might guess from the notation, a constructor sometimes behaves like a func- tion that returns an object of its class type.) Note that when you explicitly invoke a constructor with no arguments, you do include parentheses as follows: holiday = DayOfYear( ); The parentheses are only omitted when you declare a variable of the class type and want to invoke a constructor with no arguments as part of the declaration. A LWAYS I NCLUDE A D EFAULT C ONSTRUCTOR A constructor that takes no arguments is called a dd dd ee ee ff ff aa aa uu uu ll ll tt tt cc cc oo oo nn nn ss ss tt tt rr rr uu uu cc cc tt tt oo oo rr rr . This name can be mislead- ing because sometimes it is generated by default (that is, automatically) and sometimes it is not. Here is the full story. If you define a class and include absolutely no constructors of any kind, then a default constructor will be automatically created. This default constructor does not do any- thing, but it does give you an uninitialized object of the class type, which can be assigned to a variable of the class type. If your class definition includes one or more constructors of any kind, no constructor is generated automatically. So, for example, suppose you define a class called SampleClass. If you include one or more constructors that each takes one or more arguments, but you do not include a default constructor in your class definition, then there is no default con- structor and any declaration like the following will be illegal: SampleClass aVariable; The problem with the above declaration is that it asks the compiler to invoke the default construc- tor, but there is no default constructor in this case. 1 Note that this process is more complicated than simply changing the values of member vari- ables. For efficiency reasons, therefore, you may wish to retain the member functions named set to use in place of an explicit call to a constructor. default constructor 07_CH07.fm Page 265 Wednesday, August 13, 2003 12:58 PM 266 Constructors and Other Tools To make this concrete, suppose you define a class as follows: class SampleClass { public: SampleClass(int parameter1, double parameter2); void doStuff( ); private: int data1; double data2; }; You should recognize the following as a legal way to declare an object of type SampleClass and call the constructor for that class: SampleClass myVariable(7, 7.77); However, the following is illegal: SampleClass yourVariable; The compiler interprets the above declaration as including a call to a constructor with no argu- ments, but there is no definition for a constructor with zero arguments. You must either add two arguments to the declaration of yourVariable or else add a constructor definition for a con- structor with no arguments. If you redefine the class SampleClass as follows, then the above declaration of yourVariable would be legal: class SampleClass { public: SampleClass(int parameter1, double parameter2); SampleClass( ); void doStuff( ); private: int data1; double data2; }; To avoid this sort of confusion, you should always include a default constructor in any class you define. If you do not want the default constructor to initialize any member variables, you can simply give it an empty body when you implement it. The following constructor definition is per- fectly legal. It does nothing but create an uninitialized object: SampleClass::SampleClass( ) {/*Do nothing.*/} Default constructor 07_CH07.fm Page 266 Wednesday, August 13, 2003 12:58 PM Constructors 267 Self-Test Exercises 1. Suppose your program contains the following class definition (along with definitions of the member functions): class YourClass { public: YourClass(int newInfo, char moreNewInfo); YourClass( ); void doStuff( ); private: int information; char moreInformation; }; Which of the following are legal? YourClass anObject(42, ’A’); YourClass anotherObject; C ONSTRUCTORS WITH N O A RGUMENTS A constructor that takes no arguments is called a default constructor. When you declare an object and want the constructor with zero arguments to be called, you do not include any paren- theses. For example, to declare an object and pass two arguments to the constructor, you might do the following: DayOfYear date1(12, 31); However, if you want the constructor with zero arguments to be used, you declare the object as follows: DayOfYear date2; You do not declare the object as follows: DayOfYear date2( );//PROBLEM! (The problem is that this syntax declares a function that returns a DayOfYear object and has no parameters.) You do, however, include the parentheses when you explicitly invoke a constructor with no argu- ments, as shown below: date1 = DayOfYear( ); 07_CH07.fm Page 267 Wednesday, August 13, 2003 12:58 PM 268 Constructors and Other Tools Example YourClass yetAnotherObject( ); anObject = YourClass(99, ’B’); anObject = YourClass( ); anObject = YourClass; 2. What is a default constructor. Does every class have a default constructor? BankAccount C LASS Display 7.2 contains the definition of a class representing a simple bank account embedded in a small demonstration program. A bank account of this form has two pieces of data: the account balance and the interest rate. Note that we have represented the account balance as two values of type int, one for the dollars and one for the cents. This illustrates the fact that the internal repre- sentation of the data need not be simply a member variable for each conceptual piece of data. It may seem that the balance should be represented as a value of type double, rather than two int values. However, an account contains an exact number of dollars and cents, and a value of type double is, practically speaking, an approximate quantity. Moreover, a balance such as $323.52 is not a dollar sign in front of a floating-point value. The $323.52 cannot have any more or fewer than two digits after the decimal point. You cannot have a balance of $323.523, and a member variable of type double would allow such a balance. It is not impossible to have an account with fractional cents. It is just not what we want for a bank account. Note that the programmer who is using the class BankAccount can think of the balance as a value of type double or as two values of type int (for dollars and cents). The accessor and mutator functions allow the programmer to read and set the balance as either a double or two ints. The programmer who is using the class need not and should not think of any underlying member variables. That is part of the implementation that is “hidden” from the programmer using the class. Note that the mutator function setBalance, as well as the constructor names, are overloaded. Also note that all constructors and mutator functions check values to make sure they are appro- priate. For example, an interest rate cannot be negative. A balance can be negative, but you can- not have a positive number of dollars and a negative number of cents. This class has four private member functions: dollarsPart, centsPart, round, and frac- tion . These member functions are made private because they are only intended to be used in the definitions of other member functions. 07_CH07.fm Page 268 Wednesday, August 13, 2003 12:58 PM Constructors 269 Display 7.2 BankAccount Class (part 1 of 5) 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( ); 24 double getBalance( ); 25 int getDollars( ); 26 int getCents( ); 27 double getRate( );//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 Private members 07_CH07.fm Page 269 Wednesday, August 13, 2003 12:58 PM 270 Constructors and Other Tools Display 7.2 BankAccount Class (part 2 of 5) 40 int dollarsPart(double amount); 41 int centsPart(double amount); 42 int round(double number); 43 double fraction(double percent); 44 //Converts a percentage to a fraction. For example, fraction(50.3) returns 0.503. 45 }; 46 int main( ) 47 { 48 BankAccount account1(1345.52, 2.3), account2; 49 cout << "account1 initialized as follows:\n"; 50 account1.output( ); 51 cout << "account2 initialized as follows:\n"; 52 account2.output( ); 53 account1 = BankAccount(999, 99, 5.5); 54 cout << "account1 reset to the following:\n"; 55 account1.output( ); 56 cout << "Enter new data for account 2:\n"; 57 account2.input( ); 58 cout << "account2 reset to the following:\n"; 59 account2.output( ); 60 account2.update( ); 61 cout << "In one year account2 will grow to:\n"; 62 account2.output( ); 63 return 0; 64 } 65 BankAccount::BankAccount(double balance, double rate) 66 : accountDollars(dollarsPart(balance)), accountCents(centsPart(balance)) 67 { 68 setRate(rate); 69 } 70 BankAccount::BankAccount(int dollars, int cents, double rate) 71 { 72 setBalance(dollars, cents); 73 setRate(rate); 74 } 75 BankAccount::BankAccount(int dollars, double rate) 76 : accountDollars(dollars), accountCents(0) 77 { 78 setRate(rate); This declaration causes a call to the default constructor. Notice that there are no parentheses. an explicit call to the constructor BankAccount::BankAccount These functions check that the data is appropriate. 07_CH07.fm Page 270 Wednesday, August 13, 2003 12:58 PM Constructors 271 Display 7.2 BankAccount Class (part 3 of 5) 79 } 80 BankAccount::BankAccount( ): accountDollars(0), accountCents(0), rate(0.0) 81 {/*Body intentionally empty.*/} 82 void BankAccount::update( ) 83 { 84 double balance = accountDollars + accountCents*0.01; 85 balance = balance + fraction(rate)*balance; 86 accountDollars = dollarsPart(balance); 87 accountCents = centsPart(balance); 88 } 89 //Uses iostream: 90 void BankAccount::input( ) 91 { 92 double balanceAsDouble; 93 cout << "Enter account balance $"; 94 cin >> balanceAsDouble; 95 accountDollars = dollarsPart(balanceAsDouble); 96 accountCents = centsPart(balanceAsDouble); 97 cout << "Enter interest rate (NO percent sign): "; 98 cin >> rate; 99 setRate(rate); 100 } 101 //Uses iostream and cstdlib: 102 void BankAccount::output( ) 103 { 104 int absDollars = abs(accountDollars); 105 int absCents = abs(accountCents); 106 cout << "Account balance: $"; 107 if (accountDollars < 0) 108 cout << "-"; 109 cout << absDollars; 110 if (absCents >= 10) 111 cout << "." << absCents << endl; 112 else 113 cout << "." << '0' << absCents << endl; 114 cout << "Rate: " << rate << "%\n"; 115 } 116 double BankAccount::getBalance( ) 117 { 118 return (accountDollars + accountCents*0.01); 119 } For a better definition of BankAccount::input see Self-Test Exercise 3. 07_CH07.fm Page 271 Wednesday, August 13, 2003 12:58 PM 272 Constructors and Other Tools Display 7.2 Bank Account Class (part 4 of 5) 120 int BankAccount::getDollars( ) 121 { 122 return accountDollars; 123 } 124 int BankAccount::getCents( ) 125 { 126 return accountCents; 127 } 128 double BankAccount::getRate( ) 129 { 130 return rate; 131 } 132 void BankAccount::setBalance(double balance) 133 { 134 accountDollars = dollarsPart(balance); 135 accountCents = centsPart(balance); 136 } 137 //Uses cstdlib: 138 void BankAccount::setBalance(int dollars, int cents) 139 { 140 if ((dollars < 0 && cents > 0) || (dollars > 0 && cents < 0)) 141 { 142 cout << "Inconsistent account data.\n"; 143 exit(1); 144 } 145 accountDollars = dollars; 146 accountCents = cents; 147 } 148 //Uses cstdlib: 149 void BankAccount::setRate(double newRate) 150 { 151 if (newRate >= 0.0) 152 rate = newRate; 153 else 154 { 155 cout << "Cannot have a negative interest rate.\n"; 156 exit(1); 157 } 158 } 159 int BankAccount::dollarsPart(double amount) 160 { The programmer using the class does not care if the balance is stored as one real or two ints. This could be a regular function rather than a member function, but as a member functions we were able to make it private. 07_CH07.fm Page 272 Wednesday, August 13, 2003 12:58 PM . Wednesday, August 13, 2003 12:58 PM 270 Constructors and Other Tools Display 7.2 BankAccount Class (part 2 of 5) 40 int dollarsPart(double amount); 41 int centsPart(double amount); 42 int round(double. check that the data is appropriate. 07_CH07.fm Page 270 Wednesday, August 13, 2003 12:58 PM Constructors 271 Display 7.2 BankAccount Class (part 3 of 5) 79 } 80 BankAccount::BankAccount( ): accountDollars(0),. see Self-Test Exercise 3. 07_CH07.fm Page 271 Wednesday, August 13, 2003 12:58 PM 272 Constructors and Other Tools Display 7.2 Bank Account Class (part 4 of 5) 120 int BankAccount::getDollars(

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

Từ khóa liên quan

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

  • Đang cập nhật ...

Tài liệu liên quan