Tải bản đầy đủ (.pdf) (10 trang)

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

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (179.12 KB, 10 trang )

304 Operator Overloading, Friends, and References
Display 8.1 Operator Overloading
(part 1 of 5)
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 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;
24 };
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( )
30 {
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
OO
OO
vv
vv
ee
ee
rr
rr
ll
ll
oo
oo
aa
aa
dd
dd
ii

ii
nn
nn
gg
gg


UU
UU
nn
nn
aa
aa
rr
rr
yy
yy


OO
OO
pp
pp
ee
ee
rr
rr
aa
aa
tt

tt
oo
oo
rr
rr
ss
ss


For an explanation of a const on a
returned type see the subsection

RR
RR
ee
ee
tt
tt
uu
uu
rr
rr
nn
nn
ii
ii
nn
nn
gg
gg



bb
bb
yy
yy


const

VV
VV
aa
aa
ll
ll
uu
uu
ee
ee
.
08_CH08.fm Page 304 Wednesday, August 13, 2003 1:02 PM
Basic Operator Overloading 305
Display 8.1 Operator Overloading
(part 2 of 5)
40 if (yourAmount == myAmount)
41 cout << "We have the same amounts.\n";
42 else
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;
50 return 0;
51 }
52 const Money operator +(const Money& amount1, const Money& amount2)
53 {
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);
66 }
67 //Uses cstdlib:
68 const Money operator -(const Money& amount1, const Money& amount2)
69 {
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 AA
AA


CC
CC
oo
oo
nn
nn
ss
ss
tt
tt
rr
rr
uu
uu
cc
cc

tt
tt
oo
oo
rr
rr


CC
CC
aa
aa
nn
nn


RR
RR
ee
ee
tt
tt
uu
uu
rr
rr
nn
nn



aa
aa
nn
nn


OO
OO
bb
bb
jj
jj
ee
ee
cc
cc
tt
tt
.
08_CH08.fm Page 305 Wednesday, August 13, 2003 1:02 PM
306 Operator Overloading, Friends, and References
Display 8.1 Operator Overloading
(part 3 of 5)
79 finalCents = -finalCents;
80 }
81 return Money(finalDollars, finalCents);
82 }
83 bool operator
==(const Money& amount1, const Money& amount2)
84 {

85 return ((amount1.getDollars( ) == amount2.getDollars( ))
86 && (amount1.getCents( ) == amount2.getCents( )));
87 }
88 const Money operator -(const Money& amount)
89 {
90 return Money(-amount.getDollars( ), -amount.getCents( ));
91 }
92 Money::Money( ): dollars(0), cents(0)
93 {/*Body intentionally empty.*/}
94 Money::Money(double amount)
95 : dollars(dollarsPart(amount)), cents(centsPart(amount))
96 {/*Body intentionally empty*/}
97 Money::Money(int theDollars)
98 : dollars(theDollars), cents(0)
99 {/*Body intentionally empty*/}
100
101 //Uses cstdlib:
102 Money::Money(int theDollars, int theCents)
103 {
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;
111 }
112 double Money::getAmount( ) const
113 {
114 return (dollars + cents*0.01);

115 }
116 int Money::getDollars( ) const
If you prefer, you could make these
short constructor definitions inline
function definitions as discussed in
Chapter 7.
08_CH08.fm Page 306 Wednesday, August 13, 2003 1:02 PM
Basic Operator Overloading 307
Display 8.1 Operator Overloading
(part 4 of 5)
117 {
118 return dollars;
119 }
120 int Money::getCents( ) const
121 {
122 return cents;
123 }
124 //Uses iostream and cstdlib:
125 void Money::output( ) const
126 {
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 << "$-";
131 else
132 cout << ’$’;
133 cout << absDollars;
134
135 if (absCents >= 10)
136 cout << ’.’ << absCents;

137 else
138 cout << ’.’ << ’0’ << absCents;
139 }
140 //Uses iostream and cstdlib:
141 void Money::input( )
142 {
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);
154 }
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.
08_CH08.fm Page 307 Wednesday, August 13, 2003 1:02 PM
308 Operator Overloading, Friends, and References
Tip

If 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.
08_CH08.fm Page 308 Wednesday, August 13, 2003 1:02 PM
Basic Operator Overloading 309
Self-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 aa
aa
nn
nn
oo
oo
nn
nn
yy
yy


mm

mm
oo
oo
uu
uu
ss
ss


oo
oo
bb
bb
jj
jj
ee
ee
cc
cc
tt
tt
, since it is not named by any variable. However, it is still a full-fledged object. You
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?

RETURNING BY
const
VALUE
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
08_CH08.fm Page 309 Wednesday, August 13, 2003 1:02 PM
310 Operator Overloading, Friends, and References
definition 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
08_CH08.fm Page 310 Wednesday, August 13, 2003 1:02 PM
Basic Operator Overloading 311
Money 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.
1
Unless 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.
08_CH08.fm Page 311 Wednesday, August 13, 2003 1:02 PM
312 Operator Overloading, Friends, and References
Tip
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.)
08_CH08.fm Page 312 Wednesday, August 13, 2003 1:02 PM
Basic Operator Overloading 313
Self-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?

OVERLOADING UNARY OPERATORS
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
08_CH08.fm Page 313 Wednesday, August 13, 2003 1:02 PM

×