Absolute C++ (4th Edition) part 33 doc

10 151 0
Absolute C++ (4th Edition) part 33 doc

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

Thông tin tài liệu

324 Operator Overloading, Friends, and References Self-Test Exercises When one class is a friend of another class, it is typical for the classes to reference each other in their class definitions. This requires that you include a forward declara- tion to the class defined second, as illustrated in the outline that follows this paragraph. Note that the forward declaration is just the heading of the class definition followed by a semicolon. If you want the class F to be a friend of the class C, the general outline of how you set things up is as follows: class F; //forward declaration class C { public: friend class F; }; class F { Complete examples using friend classes are given in Chapter 17. We will not be using friend classes until then. 6. What is the difference between a friend function for a class and a member function for the class? 7. Complete the definition of the friend subtraction operator - in Display 8.3. 8. Suppose you wish to overload the operator < so that it applies to the type Money defined in Display 8.3. What do you need to add to the definition of Money given in Display 8.3? References and More Overloaded Operators Do not mistake the pointing finger for the moon. Zen Saying This section covers some specialized, but important, overloading topics, including overloading the assignment operator and the <<, >>, [], ++, and operators. Because forward declaration 8.3 08_CH08.fm Page 324 Wednesday, August 13, 2003 1:02 PM References and More Overloaded Operators 325 you need to understand returning a reference to correctly overload some of these oper- ators, we also discuss this topic. ■ REFERENCES A reference is the name of a storage location. 2 You can have a standalone reference, as in the following: int robert; int& bob = robert; This makes bob a reference to the storage location for the variable robert, which makes bob an alias for the variable robert. Any change made to bob will also be made to rob- ert . Stated this way, it sounds like a standalone reference is just a way to make your code confusing and get you in trouble. In most instances, a standalone reference is just R ULES ON O VERLOADING O PERATORS ■ When overloading an operator, at least one parameter (one operand) of the resulting overloaded operator must be of a class type. ■ Most operators can be overloaded as a member of the class, a friend of the class, or a nonmember, nonfriend. ■ The following operators can only be overloaded as (nonstatic) members of the class: =, [], ->, and ( ). ■ You cannot create a new operator. All you can do is overload existing operators such as +, -, *, /, %, and so forth. ■ You cannot change the number of arguments that an operator takes. For exam- ple, you cannot change % from a binary to a unary operator when you overload %; you cannot change ++ from a unary to a binary operator when you overload it. ■ You cannot change the precedence of an operator. An overloaded operator has the same precedence as the ordinary version of the operator. For example, x*y + z always means (x*y) + z, even if x, y, and z are objects and the operators + and * have been overloaded for the appropriate classes. ■ The following operators cannot be overloaded: the dot operator (.), the scope resolution operator ( ::), sizeof, ?:, and the operator .*, which is not discussed in this book. ■ An overloaded operator cannot have default arguments. 2 If you know about pointers, you will notice that a reference sounds like a pointer. A reference is essentially, but not exactly, a constant pointer. There are differences between pointers and ref- erences, and they are not completely interchangeable. reference 08_CH08.fm Page 325 Wednesday, August 13, 2003 1:02 PM 326 Operator Overloading, Friends, and References trouble, although there a few cases where it can be useful. We will not discuss standal- one references any more, nor will we use them. As you may suspect, references are used to implement the call-by-reference parame- ter mechanism. So, the concept is not completely new to this chapter, although the phrase a reference is new. We are interested in references here because returning a reference will allow you to overload certain operators in a more natural way. Returning a reference can be viewed as something like returning a variable or, more precisely, an alias to a variable. The syn- tactic details are simple. You add an & to the return type. For example: double& sampleFunction(double& variable); Since a type like double& is a different type from double, you must use the & in both the function declaration and the function definition. The return expression must be something with a reference, such as a variable of the appropriate type. It cannot be an expression, such as X + 5. Although many compilers will let you do it (with unfortu- nate results), you also should not return a local variable because you would be generat- ing an alias to a variable and immediately destroying the variable. A trivial example of the function definition is double& sampleFunction(double& variable) { return variable; } Of course, this is a pretty useless, even troublesome, function, but it illustrates the con- cept. For example, the following code will output 99 and then 42: double m = 99; cout << sampleFunction(m) << endl; sampleFunction(m) = 42; cout << m << endl; We will only be returning a reference when defining certain kinds of overloaded operators. L-V ALUES AND R-V ALUES The term l-value is used for something that can appear on the left-hand side of an assignment operator. The term r-value is used for something that can appear on the right-hand side of an assignment operator. If you want the object returned by a function to be an l-value, it must be returned by reference. 08_CH08.fm Page 326 Wednesday, August 13, 2003 1:02 PM References and More Overloaded Operators 327 Pitfall R ETURNING A R EFERENCE TO C ERTAIN M EMBER V ARIABLES When a member function returns a member variable and that member variable is of some class type, then it should normally not be returned by reference. For example, consider class A { public: const SomeClass getMember( ) { return member; } private: SomeClass member; }; where SomeClass is, of course, some class type. The function getMember should not return a reference, but should instead return by const value as we have done in the example. The problem with returning a reference to a class type member variable is the same as what we described for returning the member variable by non-const value in the programming tip section of this chapter entitled RR RR ee ee tt tt uu uu rr rr nn nn ii ii nn nn gg gg MM MM ee ee mm mm bb bb ee ee rr rr VV VV aa aa rr rr ii ii aa aa bb bb ll ll ee ee ss ss oo oo ff ff aa aa CC CC ll ll aa aa ss ss ss ss TT TT yy yy pp pp ee ee When returning a member variable which is itself of some class type it should normally be returned by const value. (Every such rule has rare exceptions.) ■ OVERLOADING >> AND << The operators >> and << can be overloaded so that you can use them to input and out- put objects of the classes you define. The details are not that different from what we have already seen for other operators, but there are some new subtleties. The insertion operator << that we used with cout is a binary operator very much like + or For example, consider the following: cout << "Hello out there.\n"; The operator is <<, the first operand is the predefined object cout (from the library iostream), and the second operand is the string value "Hello out there.\n". The pre- defined object cout is of type ostream, and so when you overload <<, the parameter that receives cout will be of type ostream. You can change either of the two operands to <<. When we cover file I/O in Chapter 12 you will see how to create an object of type ostream that sends output to a file. (These file I/O objects as well as the objects cin and cout are called streams, which is why the library name is ostream.) The overloading that we create, with cout in mind, will turn out to also work for file output without any changes in the definition of the overloaded <<. In our previous definitions of the class Money (Display 8.1 through Display 8.3) we used the member function output to output values of type Money. This is adequate, but << is an operator stream overloading 08_CH08.fm Page 327 Wednesday, August 13, 2003 1:02 PM 328 Operator Overloading, Friends, and References it would be nicer if we could simply use the insertion operator << to output values of type Money, as in the following: Money amount(100); cout << "I have " << amount << " in my purse.\n"; instead of having to use the member function output as shown below: Money amount(100); cout << "I have "; amount.output( ); cout << " in my purse.\n"; One problem in overloading the operator << is deciding what value, if any, should be returned when << is used in an expression like the following: cout << amount The two operands in the above expression are cout and amount, and evaluating the expression should cause the value of amount to be written to the screen. But if << is an operator like + or -, then the above expression should also return some value. After all, expressions with other operands, such as n1 + n2, return values. But what does cout << amount return? To obtain the answer to that question, we need to look at a more com- plicated expression involving <<. Let’s consider the following expression, which involves evaluating a chain of expres- sions using <<: cout << "I have " << amount << " in my purse.\n"; If you think of the operator << as being analogous to other operators, such as +, then the above should be (and in fact is) equivalent to the following: ( (cout << "I have ") << amount ) << " in my purse.\n"; What value should << return to make sense of the above expression? The first thing evaluated is the subexpression: (cout << "I have ") If things are to work out, then the above subexpression had better return cout so that the computation can continue as follows: ( cout << amount ) << " in my purse.\n"; And if things are to continue to work out, (cout << amount) had better also return cout so that the computation can continue as follows: cout << " in my purse.\n"; chains of << 08_CH08.fm Page 328 Wednesday, August 13, 2003 1:02 PM References and More Overloaded Operators 329 This is illustrated in Display 8.4. The operator << should return its first argument, which is of type ostream (the type of cout). Thus, the declaration for the overloaded operator << (to use with the class Money) should be as follows: class Money { public: . . . friend ostream& operator <<(ostream& outs, const Money& amount); << returns a stream Display 8.4 << as an Operator cout << "I have " << amount << " in my purse.\n"; means the same as ((cout << "I have ") << amount) << " in my purse.\n"; and is evaluated as follows: First evaluate (cout << "I have "), which returns cout: ((cout << "I have ") << amount) << " in my purse.\n"; (cout << amount) << " in my purse.\n"; Then evaluate (cout << amount), which returns cout: (cout << amount) << " in my purse.\n"; cout << " in my purse.\n"; Then evaluate cout << " in my purse.\n", which returns cout: cout << " in my purse.\n"; cout; The string "I have" is output. The string "in my purse.\n" is output. The value of amount is output. Since there are no more << operators, the process ends. 08_CH08.fm Page 329 Wednesday, August 13, 2003 1:02 PM 330 Operator Overloading, Friends, and References Once we have overloaded the insertion (output) operator <<, we will no longer need the member function output and will delete output from our definition of the class Money. The definition of the overloaded operator << is very similar to the member func- tion output. In outline form, the definition for the overloaded operator is as follows: ostream& operator <<(ostream& outputStream, const Money& amount) { <This part is the same as the body of Money::output which is given in Display 8.1 (except that dollars is replaced with amount.dollars and cents is replaced by amount.cents).> return outputStream; } Note that the operator returns a reference. The extraction operator >> is overloaded in a way that is analogous to what we described for the insertion operator <<. However, with the extraction (input) operator >>, the second argument will be the object that receives the input value, so the second parameter must be an ordinary call-by-reference parameter. In outline form the defini- tion for the overloaded extraction operator >> is as follows: istream& operator >>(istream& inputStream, Money& amount) { <This part is the same as the body of Money::input, which is given in Display 8.1 (except that dollars is replaced with amount.dollars and cents is replaced by amount.cents).> return inputStream; } The complete definitions of the overloaded operators << and >> are given in Display 8.5, where we have rewritten the class Money yet again. This time we have rewritten the class so that the operators << and >> are overloaded to allow us to use these operators with values of type Money. Note that you cannot realistically overload >> or << as member operators. If << and >> are to work as we want, then the first operand (first argument) must be cout or cin (or some file I/O stream). But if we want to overload the operators as members of, say, the class Money, then the first operand would have to be the calling object and so would have to be of type Money, and that will not allow you to define the operators so they behave in the normal way for >> and <<. << and >> return a reference 08_CH08.fm Page 330 Wednesday, August 13, 2003 1:02 PM References and More Overloaded Operators 331 Display 8.5 Overloading << and >> (part 1 of 3) 1 #include <iostream> 2 #include <cstdlib> 3 #include <cmath> 4 using namespace std; 5 //Class for amounts of money in U.S. currency 6 class Money 7 { 8 public: 9 Money( ); 10 Money(double amount); 11 Money(int theDollars, int theCents); 12 Money(int theDollars); 13 double getAmount( ) const; 14 int getDollars( ) const; 15 int getCents( ) const; 16 friend const Money operator +(const Money& amount1, const Money& amount2); 17 friend const Money operator -(const Money& amount1, const Money& amount2); 18 friend bool operator ==(const Money& amount1, const Money& amount2); 19 friend const Money operator -(const Money& amount); 20 friend ostream& operator <<(ostream& outputStream, const Money& amount); 21 friend istream& operator >>(istream& inputStream, Money& amount); 22 private: 23 int dollars; //A negative amount is represented as negative dollars and 24 int cents; //negative cents. Negative $4.50 is represented as -4 and -50. 25 int dollarsPart(double amount) const; 26 int centsPart(double amount) const; 27 int round(double number) const; 28 }; 29 int main( ) 30 { 31 Money yourAmount, myAmount(10, 9); 32 cout << "Enter an amount of money: "; 33 cin >> yourAmount; 34 cout << "Your amount is " << yourAmount << endl; 35 cout << "My amount is " << myAmount << endl; 36 37 if (yourAmount == myAmount) 38 cout << "We have the same amounts.\n"; 39 else 40 cout << "One of us is richer.\n"; 41 Money ourAmount = yourAmount + myAmount; 08_CH08.fm Page 331 Wednesday, August 13, 2003 1:02 PM 332 Operator Overloading, Friends, and References Display 8.5 Overloading << and >> (part 2 of 3) 42 cout << yourAmount << " + " << myAmount 43 << " equals " << ourAmount << endl; 44 Money diffAmount = yourAmount - myAmount; 45 cout << yourAmount << " - " << myAmount 46 << " equals " << diffAmount << endl; 47 return 0; 48 } < Definitions of other member functions are as in Display 8.1. Definitions of other overloaded operators are as in Display 8.3. > 49 ostream& operator <<(ostream& outputStream, const Money& amount) 50 { 51 int absDollars = abs(amount.dollars); 52 int absCents = abs(amount.cents); 53 if (amount.dollars < 0 || amount.cents < 0) 54 //accounts for dollars == 0 or cents == 0 55 outputStream << "$-"; 56 else 57 outputStream << ’$’; 58 outputStream << absDollars; 59 if (absCents >= 10) 60 outputStream << ’.’ << absCents; 61 else 62 outputStream << ’.’ << ’0’ << absCents; 63 return outputStream; 64 } 65 66 //Uses iostream and cstdlib: 67 istream& operator >>(istream& inputStream, Money& amount) 68 { 69 char dollarSign; 70 inputStream >> dollarSign; //hopefully 71 if (dollarSign != ’$’) 72 { 73 cout << "No dollar sign in Money input.\n"; 74 exit(1); 75 } 76 double amountAsDouble; 77 inputStream >> amountAsDouble; 78 amount.dollars = amount.dollarsPart(amountAsDouble); Since << returns a reference, you can chain << like this. You can chain >> in a similar way. In the main function, cout is plugged in for outputStream. For an alternate input algorithm, see Self-Test Exercise 3 in Chapter 7. Returns a reference In the main function, cin is plugged in for inputStream. Since this is not a member operator, you need to specify a calling object for member functions of Money. 08_CH08.fm Page 332 Wednesday, August 13, 2003 1:02 PM References and More Overloaded Operators 333 Self-Test Exercises 9. In Display 8.5, the definition of the overloaded operator << contains lines like the fol- lowing: outputStream << "$-"; Isn’t this circular? Aren’t we defining << in terms of <<? 10. Why can’t we overload << or >> as member operators? 11. Below is the definition for a class called Percent. Objects of type Percent represent per- centages such as 10% or 99%. Give the definitions of the overloaded operators >> and << so that they can be used for input and output with objects of the class Percent. Assume that input always consists of an integer followed by the character ’%’, such as 25%. All per- centages are whole numbers and are stored in the int member variable named value. You do not need to define the other overloaded operators and do not need to define the con- structor. You only have to define the overloaded operators >> and <<. #include <iostream> using namespace std; class Percent { public: friend bool operator ==(const Percent& first, const Percent& second); friend bool operator <(const Percent& first, const Percent& second); Percent( ); Display 8.5 Overloading << and >> (part 3 of 3) 79 amount.cents = amount.centsPart(amountAsDouble); 80 return inputStream; 81 } S AMPLE D IALOGUE \ Enter an amount of money: $123.45 Your amount is $123.45 My amount is $10.09. One of us is richer. $123.45 + $10.09 equals $133.54 $123.45 - $10.09 equals $113.36 Returns a reference 08_CH08.fm Page 333 Wednesday, August 13, 2003 1:02 PM . return a reference 08_CH08.fm Page 330 Wednesday, August 13, 2003 1:02 PM References and More Overloaded Operators 331 Display 8.5 Overloading << and >> (part 1 of 3) 1 #include <iostream> 2. + myAmount; 08_CH08.fm Page 331 Wednesday, August 13, 2003 1:02 PM 332 Operator Overloading, Friends, and References Display 8.5 Overloading << and >> (part 2 of 3) 42 cout <<. object for member functions of Money. 08_CH08.fm Page 332 Wednesday, August 13, 2003 1:02 PM References and More Overloaded Operators 333 Self-Test Exercises 9. In Display 8.5, the definition

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

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

Tài liệu liên quan