21 int dollarsPart double amount const ; 22 int centsPart double amount const ; 23 int round double number const ; 25 const Money operator + const Money& amount1, const Money& amount2; 2
Trang 1Display 8.1 Operator Overloading (part 1 of 5)
1 #include <iostream>
2 #include <cstdlib>
3 #include <cmath>
4 using namespace std;
6 class Money
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 void input( ); //Reads the dollar sign as well as the amount number.
17 void output( ) const ;
18 private :
19 int dollars; //A negative amount is represented as negative dollars and
20 int cents; //negative cents Negative $4.50 is represented as -4 and -50.
21 int dollarsPart( double amount) const ;
22 int centsPart( double amount) const ;
23 int round( double number) const ;
25 const Money operator +( const Money& amount1, const Money& amount2);
26 const Money operator -( const Money& amount1, const Money& amount2);
27 bool operator ==( const Money& amount1, const Money& amount2);
28 const Money operator -( const Money& amount);
29 int main( )
31 Money yourAmount, myAmount(10, 9);
32 cout << "Enter an amount of money: ";
33 yourAmount.input( );
34 cout << "Your amount is ";
35 yourAmount.output( );
36 cout << endl;
37 cout << "My amount is ";
38 myAmount.output( );
39 cout << endl;
This is a unary operator and is discussed in the subsection O
Ovvvveeeerrrrllllooo oaaaad d diiiinn ng n g U g U Unn n naaaarrrryyy y O O Op peeeerrrraaaattttooo p orrrrssss
For an explanation of a const on a returned type see the subsection RRR
Reeeettttuuu urrrrnn n niiiinn n ng g g b b byyyy const VV Vaaaalllluuu ueeee.
Trang 2Display 8.1 Operator Overloading (part 2 of 5)
40 if (yourAmount == myAmount)
41 cout << "We have the same amounts.\n";
43 cout << "One of us is richer.\n";
44 Money ourAmount = yourAmount + myAmount;
45 yourAmount.output( ); cout << " + "; myAmount.output( );
46 cout << " equals "; ourAmount.output( ); cout << endl;
47 Money diffAmount = yourAmount - myAmount;
48 yourAmount.output( ); cout << " - "; myAmount.output( );
49 cout << " equals "; diffAmount.output( ); cout << endl;
52 const Money operator +( const Money& amount1, const Money& amount2)
54 int allCents1 = amount1.getCents( ) + amount1.getDollars( )*100;
55 int allCents2 = amount2.getCents( ) + amount2.getDollars( )*100;
56 int sumAllCents = allCents1 + allCents2;
57 int absAllCents = abs(sumAllCents); //Money can be negative.
58 int finalDollars = absAllCents/100;
59 int finalCents = absAllCents%100;
60 if (sumAllCents < 0)
61 {
62 finalDollars = -finalDollars;
63 finalCents = -finalCents;
64 }
65 return Money(finalDollars, finalCents);
68 const Money operator -( const Money& amount1, const Money& amount2)
70 int allCents1 = amount1.getCents( ) + amount1.getDollars( )*100;
71 int allCents2 = amount2.getCents( ) + amount2.getDollars( )*100;
72 int diffAllCents = allCents1 - allCents2;
73 int absAllCents = abs(diffAllCents);
74 int finalDollars = absAllCents/100;
75 int finalCents = absAllCents%100;
76 if (diffAllCents < 0)
77 {
78 finalDollars = -finalDollars;
Note that we need to use accessor and mutator functions.
If the return statements puzzle you, see the tip entitled A A A CCC Cooo onn nssssttttrrrruuu n uccccttttooo orrrr CCC Caaaann n n RRR
Reeeettttuuu urrrrnn n n aaaann n O n O Ob b bjjjjeeeecccctttt.
Trang 3Display 8.1 Operator Overloading (part 3 of 5)
79 finalCents = -finalCents;
80 }
81 return Money(finalDollars, finalCents);
83 bool operator ==( const Money& amount1, const Money& amount2)
85 return ((amount1.getDollars( ) == amount2.getDollars( ))
86 && (amount1.getCents( ) == amount2.getCents( )));
88 const Money operator -( const Money& amount)
90 return Money(-amount.getDollars( ), -amount.getCents( ));
92 Money::Money( ): dollars(0), cents(0)
94 Money::Money( double amount)
95 : dollars(dollarsPart(amount)), cents(centsPart(amount))
97 Money::Money( int theDollars)
98 : dollars(theDollars), cents(0)
100
102 Money::Money( int theDollars, int theCents)
104 if ((theDollars < 0 && theCents > 0) || (theDollars > 0 && theCents < 0))
105 {
106 cout << "Inconsistent money data.\n";
107 exit(1);
108 }
109 dollars = theDollars;
110 cents = theCents;
112 double Money::getAmount( ) const
114 return (dollars + cents*0.01);
116 int Money::getDollars( ) const
If you prefer, you could make these short constructor definitions inline function definitions as discussed in Chapter 7.
Trang 4Display 8.1 Operator Overloading (part 4 of 5)
118 return dollars;
120 int Money::getCents( ) const
122 return cents;
125 void Money::output( ) const
127 int absDollars = abs(dollars);
128 int absCents = abs(cents);
129 if (dollars < 0 || cents < 0) //accounts for dollars == 0 or cents == 0
130 cout << "$-";
132 cout << ’$’;
133 cout << absDollars;
134
135 if (absCents >= 10)
136 cout << ’.’ << absCents;
138 cout << ’.’ << ’0’ << absCents;
141 void Money::input( )
143 char dollarSign;
144 cin >> dollarSign; //hopefully
145 if (dollarSign != ’$’)
146 {
147 cout << "No dollar sign in Money input.\n";
148 exit(1);
149 }
150 double amountAsDouble;
151 cin >> amountAsDouble;
152 dollars = dollarsPart(amountAsDouble);
153 cents = centsPart(amountAsDouble);
155 int Money::dollarsPart( double amount) const
156 <The rest of the definition is the same as BankAccount::dollarsPart in Display 7.2.>
For a better definition of the input function, see Self-Test Exercise 3 in Chapter 7.
Trang 5If you look at the main function in the demonstration program in Display 8.1, you will see that the overloaded binary operators +, -, and == are used with objects of the class Money in the same way that +, -, and == are used with the predefined types, such as
int and double You can overload most but not all operators One major restriction on overloading
an operator is that at least one operand must be of a class type So, for example, you can overload the % operator to apply to two objects of type Money or to an object of type
Money and a double, but you cannot overload % to combine two doubles
A C ONSTRUCTOR C AN R ETURN AN O BJECT
We often think of a constructor as if it were a void function However, constructors are special functions with special properties, and sometimes it makes more sense to think of them as
return-Display 8.1 Operator Overloading (part 5 of 5)
157 int Money::centsPart( double amount) const
158 <The rest of the definition is the same as BankAccount::centsPart in Display 7.2.>
159 int Money::round( double number) const
160 <The rest of the definition is the same as BankAccount::round in Display 7.2.>
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
O PERATOR O VERLOADING
A (binary) operator, such as + , - , / , % , and so forth, is simply a function that is called using a dif-ferent syntax for listing its arguments With a binary operator, the arguments are listed before and after the operator; with a function the arguments are listed in parentheses after the function name An operator definition is written similar to a function definition, except that the operator definition includes the reserved word operator before the operator name The predefined oper-ators, such as + , - , and so forth, can be overloaded by giving them a new definition for a class type An example of overloading the + , - , and == operators is given in Display 8.1.
Trang 6Self-Test Exercises
ing a value Notice the return statement in the definition of the overloaded + operator in Display 8.1, which we repeat below:
return Money(finalDollars, finalCents);
The expression that is returned is an invocation of the constructor for Money Although we some-times think of a constructor as a void function, a constructor constructs an object and can also
be thought of as returning an object of the class If you feel uncomfortable with this use of the constructor, it may help to know that this return statement is equivalent to the following, more cumbersome and less efficient, code:
Money temp;
temp = Money(finalDollars, finalCents);
return temp;
An expression, such as Money(finalDollars, finalCents) , is sometimes called an aaa ann n nooon nyyy y m
mooo ouu ussss ooo u ob bjjjjeeeecccctttt, since it is not named by any variable However, it is still a full-fledged object You b can even use it as a calling object, as in the following:
Money(finalDollars, finalCents).getDollars( ) The previous expression returns the int value of finalDollars
1 What is the difference between a (binary) operator and a function?
2 Suppose you wish to overload the operator < so that it applies to the type Money defined in Display 8.1 What do you need to add to the definition of Money given in Display 8.1?
3 Is it possible using operator overloading to change the behavior of + on integers? Why or why not?
Notice the returned types in the declarations for overloaded operators for the class
Money in Display 8.1 For example, the following is the declaration for the overloaded plus operator as it appears in Display 8.1:
const Money operator +( const Money& amount1, const Money& amount2);
This subsection explains the const at the start of the line But before we discuss that first
const, let’s make sure we understand all the other details about returning a value So, let’s first consider the case where that const does not appear in either the declaration or
anonymous object
Trang 7definition of the overloaded plus operator Let’s suppose that the declaration reads as follows:
Money operator +( const Money& amount1, const Money& amount2);
and let’s see what we can do with the value returned
When an object is returned, for example, (m1 + m2), where m1 and m2 are of type
Money, the object can be used to invoke a member function, which may or may not change the value of the member variables in the object (m1 + m2) For example,
(m1 + m2).output( );
is perfectly legal In this case, it does not change the object (m1 + m2) However, if we omitted the const before the type returned for the plus operator, then the following would be legal and would change the values of the member variables of the object
(m1 + m2):
(m1 + m2).input( );
So, objects can be changed, even when they are not associated with any variable One way to make sense of this is to note that objects have member variables and thus have some kinds of variables that can be changed
Now let’s assume that everything is as shown in Display 8.1; that is, there is a const
before the returned type of each operator that returns an object of type Money For example, below is the declaration for the overloaded plus operator as it appears in Dis-play 8.1:
const Money operator +( const Money& amount1, const Money& amount2);
The first const on the line is a new use of the const modifier This is called returning
a value as const or returning by const value or returning by constant value What
the const modifier means in this case is that the returned object cannot be changed For example, consider the following code:
Money m1(10.99), m2(23.57);
(m1 + m2).output( );
The invocation of output is perfectly legal because it does not change the object
(m1 + m2) However, with that const before the returned type, the following will pro-duce a compiler error message:
(m1 + m2).input( );
Why would you want to return by const value? It provides a kind of automatic error checking When you construct (m1 + m2), you do not want to inadvertently change it
At first this protection from changing an object may seem like too much protection, since you can have
return by
constant value
Trang 8Money m3;
m3 = (m1 + m2);
and you very well may want to change m3 No problem—the following is perfectly legal:
m3 = (m1 + m2);
m3.input( );
The values of m3 and (m1 + m2) are two different objects The assignment operator does not make m3 the same as the object (m1 + m2) Instead, it copies the values of the member variables of (m1 + m2) into the member variables of m3 With objects of a class, the default assignment operator does not make the two objects the same object, it only copies values of member variables from one object to another object
This distinction is subtle but important It may help you understand the details if you recall that a variable of a class type and an object of a class type are not the same thing An object is a value of a class type and may be stored in a variable of a class type, but the variable and the object are not the same thing In the code
m3 = (m1 + m2);
the variable m3 and its value (m1 + m2) are different things, just as n and 5 are different things in
int n = 5;
or in int n = (2 + 3);
It may take you a while to become comfortable with this notion of return by const
value In the meantime, a good rule of thumb is to always return class types by const
value unless you have an explicit reason not to do so For most simple programs this will have no effect on your program other than to flag some subtle errors
Note that although it is legal, it is pointless to return basic types, such as int, by
const value The const has no effect in the case of basic types When a function or oper-ator returns a value of one of the basic types, such as int, double, or char, it returns the value, such as 5, 5.5, or ’A’ It does not return a variable or anything like a variable.1 Unlike a variable, the value cannot be changed—you cannot change 5 Values of a basic type cannot be changed whether there is a const before the returned type or not On the other hand, values of a class type—that is, objects—can be changed, since they have member variables, and so the const modifier has an effect on the object returned
1Unless the value returned is returned by reference, but return by reference is a topic covered later in this chapter Here we assume the value is not returned by reference
Trang 9Tip R ETURNING M EMBER V ARIABLES OF A C LASS T YPE
When returning a member variable of a class type, in almost all cases it is important to return the member value by const value To see why, suppose you do not, as in the example outlined in what follows:
class Employee {
public : Money getSalary( ) { return salary; }
private : Money salary;
};
In this example, salary is a private member variable that should not be changeable except by using some accessor function of the class Employee However, this privateness is easily circum-vented as follows:
Employee joe;
(joe.getSalary( )).input( );
The lucky employee named joe can now enter any salary she wishes!
On the other hand, suppose getSalary returns its value by const value, as follows:
class Employee {
public : const Money getSalary( ) { return salary; }
private : Money salary;
};
In this case, the following will give a compiler error message.
(joe.getSalary( )).input( );
(The declaration for getSalary should ideally be const Money getSalary( ) const { return salary; } but we did not want to confuse the issue with another kind of const )
Trang 10Self-Test Exercises
4 Suppose you omit the const at the beginning of the declaration and definition of the over-loaded plus operator for the class Money, so that the value is not returned by const value Is the following legal?
Money m1(10.99), m2(23.57), m3(12.34);
(m1 + m2) = m3;
Is it legal if the definition of the class Money is as shown in Display 8.1, so that the plus operator returns its value by const value?
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 opera-tor - is used to set the value of a variable x equal to the negative of the value of the vari-able y:
x = -y;
The increment and decrement operators, ++ and , are other examples of unary oper-ators
You can overload unary operators as well as binary operators For example, we have overloaded the minus operator - for the type Money (Display 8.1) so that it has both a unary and a binary operator version of the subtraction/negation operator - For exam-ple, suppose your program contains this class definition and the following code:
Money amount1(10), amount2(6), amount3;
Then the following sets the value of amount3 to amount1 minus amount2:
amount3 = amount1 - amount2;
The following will, then, output $4.00 to the screen:
amount3.output( );
On the other hand, the following will set amount3 equal to the negative of amount1:
amount3 = -amount1;
The following will, then, output -$10.00 to the screen:
amount3.output( );
unary operator