1. Trang chủ
  2. » Công Nghệ Thông Tin

Absolute C++ (4th Edition) part 32 pptx

10 275 0

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

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 197,76 KB

Nội dung

314 Operator Overloading, Friends, and References You can overload the ++ and operators in ways similar to how we overloaded the negation operator in Display 8.1. If you overload the ++ and operators following the example of the minus sign - in Display 8.1, then the overloading definition will apply to the operator when it is used in prefix position, as in ++x and x. Later in this chap- ter we will discuss overloading ++ and more fully and will then explain how to over- load these operators for use in the postfix position. ■ OVERLOADING AS MEMBER FUNCTIONS In Display 8.1 we overloaded operators as standalone functions defined outside the class. It is also possible to overload an operator as a member operator (member func- tion). This is illustrated in Display 8.2. Note that when a binary operator is overloaded as a member operator, there is only one parameter, not two. The calling object serves as the first parameter. For example, consider the following code: Money cost(1, 50), tax(0, 15), total; total = cost + tax; When + is overloaded as a member operator, then in the expression cost + tax the variable cost is the calling object and tax is the single argument to +. The definition of the member operator + is given in Display 8.2. Notice the follow- ing line from that definition: int allCents1 = cents + dollars*100; The expressions cents and dollars are member variables of the calling object, which in this case is the first operand. If this definition is applied to cost + tax then cents means cost.cents and dollars means cost.dollars. Note that since the first operand is the calling object, you should, in most cases, add the const modifier to the end of the operator declaration and to the end of the operator definition. Whenever the operator invocation does not change the calling object (which is the first operand), good style dictates that you add the const to the end of the operator declaration and to the end of the operator definition, as illustrated in Display 8.2. Overloading an operator as a member variable can seem strange at first, but it is easy to get used to the new details. Many experts advocate always overloading operators as member operators rather than as nonmembers (as in Display 8.1): It is more in the spirt of object-oriented programming and is a bit more efficient, since the definition can directly reference member variables and need not use accessor and mutator func- tions. However, as we will discover later in this chapter, overloading an operator as a member also has a significant disadvantage. ++ and 08_CH08.fm Page 314 Wednesday, August 13, 2003 1:02 PM Basic Operator Overloading 315 Display 8.2 Overloading Operators as Members (part 1 of 2) 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 dollars, int cents); 12 Money(int dollars); 13 double getAmount( ) const; 14 int getDollars( ) const; 15 int getCents( ) const; 16 void input( ); //Reads the dollar sign as well as the amount number. 17 void output( ) const; 18 const Money operator +(const Money& amount2) const; 19 const Money operator -(const Money& amount2) const; 20 bool operator ==(const Money& amount2) const; 21 const Money operator -( ) const; 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 < If the main function is the same as in Display 8.1, then the screen dialogue will be the same as shown in Display 8.1. > 32 } 33 34 const Money Money::operator +(const Money& secondOperand) const 35 { 36 int allCents1 = cents + dollars*100; 37 int allCents2 = secondOperand.cents + secondOperand.dollars*100; 38 int sumAllCents = allCents1 + allCents2; 39 int absAllCents = abs(sumAllCents); //Money can be negative. 40 int finalDollars = absAllCents/100; 41 int finalCents = absAllCents%100; This is Display 8.1 redone with the overloaded operators as member functions. The calling object is the first operand. 08_CH08.fm Page 315 Wednesday, August 13, 2003 1:02 PM 316 Operator Overloading, Friends, and References Tip A C LASS H AS A CCESS TO A LL I TS O BJECTS When defining a member function or operator, you may access any private member variable (or function) of the calling object. However, you are allowed even more than that. You may access any private member variable (or private member function) of any object of the class being defined. For example, consider the following few lines that begin the definition of the plus operator for the class Money in Display 8.2: const Money Money::operator +(const Money& secondOperand) const { int allCents1 = cents + dollars*100; int allCents2 = secondOperand.cents + secondOperand.dollars*100; In this case, the plus operator is being defined as a member operator, so the variables cents and dollars, in the first line of the function body, are the member variables of the calling object Display 8.2 Overloading Operators as Members (part 2 of 2) 42 if (sumAllCents < 0) 43 { 44 finalDollars = -finalDollars; 45 finalCents = -finalCents; 46 } 47 return Money(finalDollars, finalCents); 48 } 49 const Money Money::operator -(const Money& secondOperand) const 50 < The rest of this definition is Self-Test Exercise 5. > 51 bool Money::operator ==(const Money& secondOperand) const 52 { 53 return ((dollars == secondOperand.dollars) 54 && (cents == secondOperand.cents)); 55 } 56 const Money Money::operator -( ) const 57 { 58 return Money(-dollars, -cents); 59 } 60 < Definitions of all other member functions are the same as in Display 8.1. > 08_CH08.fm Page 316 Wednesday, August 13, 2003 1:02 PM Basic Operator Overloading 317 Pitfall Self-Test Exercises (which happens to be the first operand). However, it is also legal to access by name the member variables of the object secondOperand, as in the following line: int allCents2 = secondOperand.cents + secondOperand.dollars*100; This is legal because secondOperand is an object of the class Money and this line is in the defini- tion of a member operator for the class Money. Many novice programmers mistakenly think they only have direct access to the private members of the calling object and do not realize that they have direct access to all objects of the class being defined. 5. Complete the definition of the member binary operator - in Display 8.2. ■ OVERLOADING FUNCTION APPLICATION ( ) The function call operator ( ) must be overloaded as a member function. It allows you to use an object of the class as if it were a function. If class AClass has overloaded the function application operator to have one argument of type int and anObject is an object of AClass, then anObject(42) invokes the overloaded function call operator ( ) with calling object anObject and argument 42. The type returned may be void or any other type. The function call operator ( ) is unusual in that it allows any number of arguments. So, you can define several overloaded versions of the function call operator ( ). O VERLOADING && , || , AND THE C OMMA O PERATOR The predefined versions of && and || that work for the type bool use short-circuit evaluation. However, when overloaded these operators perform complete evaluation. This is so contrary to what most programmers expect that it inevitably causes problems. It is best to just not overload these two operators. The comma operator also presents problems. In its normal use the comma operator guarantees left-to-right evaluations. When overloaded no such guarantee is given. The comma operator is another operator it is safest to avoid overloading. 08_CH08.fm Page 317 Wednesday, August 13, 2003 1:02 PM 318 Operator Overloading, Friends, and References Friend Functions and Automatic Type Conversion Trust your friends. Common advice Friend functions are nonmember functions that have all the privileges of member func- tions. Before we discuss friend functions in any detail, we discuss automatic type con- version via constructors, since that helps to explain one of the advantages of overloading operators (or any functions) as friend functions. ■ CONSTRUCTORS FOR AUTOMATIC TYPE CONVERSION If your class definition contains the appropriate constructors, the system will perform certain type conversions automatically. For example, if your program contains the defi- nition of the class Money either as given in Display 8.1 or as given in Display 8.2, you could use the following in your program: Money baseAmount(100, 60), fullAmount; fullAmount = baseAmount + 25; fullAmount.output( ); The output would be $125.60 The code above may look simple and natural enough, but there is one subtle point. The 25 (in the expression baseAmount + 25) is not of the appropriate type. In Display 8.1 we only overloaded the operator + so that it could be used with two values of type Money. We did not overload + so that it could be used with a value of type Money and an integer. The constant 25 can be considered to be of type int, but 25 cannot be used as a value of type Money unless the class definition somehow tells the system how to con- vert an integer to a value of type Money. The only way that the system knows that 25 means $25.00 is that we included a constructor that takes a single argument of type int. When the system sees the expression baseAmount + 25 it first checks to see if the operator + has been overloaded for the combination of a value of type Money and an integer. Since there is no such overloading, the system next looks to see if there is a constructor that takes a single argument that is an integer. If it finds a constructor that takes a single integer argument, it uses that constructor to con- vert the integer 25 to a value of type Money. The one-argument constructor says that 25 should be converted to an object of type Money whose member variable dollars is equal to 25 and whose member variable cents is equal to 0. In other words, the con- 8.2 08_CH08.fm Page 318 Wednesday, August 13, 2003 1:02 PM Friend Functions and Automatic Type Conversion 319 Pitfall structor converts 25 to an object of type Money that represents $25.00. (The definition of the constructor is in Display 8.1.) Note that this type conversion will not work unless there is a suitable constructor. If the class Money did not contain a constructor with one parameter of type int (or of some other number type, such as long or double), then the expression baseAmount + 25 would produce an error message. These automatic type conversions (produced by constructors) seem most common and compelling with overloaded numeric operators such as + and However, these automatic conversions apply in exactly the same way to arguments of ordinary func- tions, arguments of member functions, and arguments of other overloaded operators. M EMBER O PERATORS AND A UTOMATIC T YPE C ONVERSION When you overload a binary operator as a member operator, the two arguments are no longer symmetric. One is a calling object, and only the second “argument” is a true argument. This is not only unaesthetic but also has a very practical shortcoming. Any automatic type conversion will only apply to the second argument. So, for example, as we noted in the previous subsection, the following would be legal: Money baseAmount(100, 60), fullAmount; fullAmount = baseAmount + 25; This is because Money has a constructor with one argument of type int, and so the value 25 will be considered an int value that is automatically converted to a value of type Money. However, if you overload + as a member operator (as in Display 8.2), then you cannot reverse the two arguments to +. The following is illegal: fullAmount = 25 + baseAmount; because 25 cannot be a calling object. Conversion of int values to type Money works for argu- ments but not for calling objects. On the other hand, if you overload + as a nonmember (as in Display 8.1), then the following is per- fectly legal: fullAmount = 25 + baseAmount; This is the biggest advantage of overloading an operator as a nonmember. Overloading an operator as a nonmember gives you automatic type conversion of all arguments. Overloading an operator as a member gives you the efficiency of bypassing accessor and mutator functions and directly accessing member variables. There is a way to overload an operator (and certain functions) that offers both of these advantages. It is called overloading as a friend func- tion and is our next topic. 08_CH08.fm Page 319 Wednesday, August 13, 2003 1:02 PM 320 Operator Overloading, Friends, and References ■ FRIEND FUNCTIONS If your class has a full set of accessor and mutator functions, you can use the accessor and mutator functions to define nonmember overloaded operators (as in Display 8.1 as opposed to Display 8.2). However, although this may give you access to the private member variables, it may not give you efficient access to them. Look again at the defi- nition of the overloaded addition operator + given in Display 8.1. Rather than just reading four member variables, it must incur the overhead of two invocations of get- Cents and two invocations of getDollars. This adds a bit of inefficiency and also can make the code harder to understand. The alternative of overloading + as a member gets around this problem at the price of losing automatic type conversion of the first oper- and. Overloading the + operator as a friend will allow us to both directly access mem- ber variables and have automatic type conversion for all operands. A friend function of a class is not a member function of the class, but it has access to the private members of that class (to both private member variables and private member functions) just as a member function does. To make a function a friend func- tion, you must name it as a friend in the class definition. For example, in Display 8.3 we have rewritten the definition of the class Money yet another time. This time we have overloaded the operators as friends. You make an operator or function a friend of a class by listing the operator or function declaration in the definition of the class and placing the keyword friend in front of the operator or function declaration. A friend operator or friend function has its declaration listed in the class definition, just as you would list the declaration of a member function, except that you precede the declaration by the keyword friend. However, a friend is not a member function; rather, it really is an ordinary function with extraordinary access to the data members of the class. The friend is defined exactly like the ordinary function it is. In particular, the oper- ator definitions shown in Display 8.3 do not include the qualifier Money:: in the func- tion heading. Also, you do not use the keyword friend in the function definition (only in the function declaration). The friend operators in Display 8.3 are invoked just like the nonfriend, nonmember operators in Display 8.1, and they have automatic type con- version of all arguments just like the nonfriend, nonmember operators in Display 8.1. The most common kinds of friend functions are overloaded operators. However, any kind of function can be made a friend function. A function (or overloaded operator) can be a friend of more than one class. To make it a friend of multiple classes, just give the declaration of the friend function in each class for which you want it to be a friend. Many experts consider friend functions (and operators) to be in some sense not “pure.” They feel that in the true spirit of object-oriented programming all operators and functions should be member functions. On the other hand, overloading operators as friends provides the pragmatic advantage of automatic type conversion in all argu- ments, and since the operator declaration is inside the class definitions, it provides at least a bit more encapsulation than nonmember, nonfriend operators. We have shown you three ways to overload operators: as nonmember nonfriends, as members, and as friends. You can decide for yourself which technique you prefer. friend function 08_CH08.fm Page 320 Wednesday, August 13, 2003 1:02 PM Friend Functions and Automatic Type Conversion 321 Display 8.3 Overloading Operators as Friends (part 1 of 2) 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 dollars, int cents); 12 Money(int dollars); 13 double getAmount( ) const; 14 int getDollars( ) const; 15 int getCents( ) const; 16 void input( ); //Reads the dollar sign as well as the amount number. 17 void output( ) const; 18 friend const Money operator +(const Money& amount1, const Money& amount2); 19 friend const Money operator -(const Money& amount1, const Money& amount2); 20 friend bool operator ==(const Money& amount1, const Money& amount2); 21 friend const Money operator -(const 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 < If the main function is the same as in Display 8.1, then the screen dialogue will be the same as shown in Display 8.1. > 32 } 33 34 const Money operator +(const Money& amount1, const Money& amount2) 35 { 36 int allCents1 = amount1.cents + amount1.dollars*100; 37 int allCents2 = amount2.cents + amount2.dollars*100; 38 int sumAllCents = allCents1 + allCents2; 39 int absAllCents = abs(sumAllCents); //Money can be negative. 40 int finalDollars = absAllCents/100; 08_CH08.fm Page 321 Wednesday, August 13, 2003 1:02 PM 322 Operator Overloading, Friends, and References Display 8.3 Overloading Operators as Friends (part 2 of 2) 41 int finalCents = absAllCents%100; 42 if (sumAllCents < 0) 43 { 44 finalDollars = -finalDollars; 45 finalCents = -finalCents; 46 } 47 return Money(finalDollars, finalCents); 48 } 49 const Money operator -(const Money& amount1, const Money& amount2) 50 < The complete definition is Self-Test Exercise 7. > 51 bool operator ==(const Money& amount1, const Money& amount2) 52 { 53 return ((amount1.dollars == amount2.dollars) 54 && (amount1.cents == amount2.cents)); 55 } 56 const Money operator -(const Money& amount) 57 { 58 return Money(-amount.dollars, -amount.cents); 59 } < Definitions of all other member functions are the same as in Display 8.1. > 60 Note that friends have direct access to member variables. F RIEND F UNCTIONS A friend function of a class is an ordinary function except that it has access to the private members of objects of that class. To make a function a friend of a class, you must list the function declaration for the friend function in the class definition. The function declaration is preceded by the keyword friend. The function declaration may be placed in either the private section or the public section, but it will be a public function in either case, so it is clearer to list it in the public section. S YNTAX OF A C LASS D EFINITION WITH F RIEND F UNCTIONS class Class_Name { public: friend Declaration_for_Friend_Function_1 friend Declaration_for_Friend_Function_2 . . . You need not list the friend functions first. You can intermix the order of these declarations. 08_CH08.fm Page 322 Wednesday, August 13, 2003 1:02 PM Friend Functions and Automatic Type Conversion 323 Pitfall C OMPILERS WITHOUT F RIENDS On some C++ compilers friend functions simply do not work as they are supposed to work. Worst of all, they may work sometimes and not work at other times. On these compilers friend functions do not always have access to private members of the class as they are supposed to. Presumably, this will be fixed in later releases of these compilers. In the meantime, you will have to work around this problem. If you have one of these compilers for which friend functions do not work, you must either use accessor functions to define nonmember functions and overloaded operators or you must overload operators as members. ■ FRIEND CLASSES A class can be a friend of another class in the same way that a function can be a friend of a class. If the class F is a friend of the class C, then every member function of the class F is a friend of the class C. To make one class a friend of another, you must declare the friend class as a friend within the other class. Member_Function_Declarations private: Private_Member_Declarations }; E XAMPLE class FuelTank { public: friend void fillLowest(FuelTank& t1, FuelTank& t2); //Fills the tank with the lowest fuel level, or t1 if a tie. FuelTank(double theCapacity, double theLevel); FuelTank( ); void input( ); void output( ) const; private: double capacity;//in liters double level; }; A friend function is not a member function. A friend function is defined and called the same way as an ordinary function. You do not use the dot operator in a call to a friend function, and you do not use a type qualifier in the definition of a friend function. friend class 08_CH08.fm Page 323 Wednesday, August 13, 2003 1:02 PM . prefer. friend function 08_CH08.fm Page 320 Wednesday, August 13, 2003 1:02 PM Friend Functions and Automatic Type Conversion 321 Display 8.3 Overloading Operators as Friends (part 1 of 2) 1 #include <iostream> 2. absAllCents/100; 08_CH08.fm Page 321 Wednesday, August 13, 2003 1:02 PM 322 Operator Overloading, Friends, and References Display 8.3 Overloading Operators as Friends (part 2 of 2) 41 int finalCents. these declarations. 08_CH08.fm Page 322 Wednesday, August 13, 2003 1:02 PM Friend Functions and Automatic Type Conversion 323 Pitfall C OMPILERS WITHOUT F RIENDS On some C++ compilers friend functions

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

TỪ KHÓA LIÊN QUAN