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

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

10 152 0
Tài liệu đã được kiểm tra trùng lặp

Đ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 199,2 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Self-Test ExercisesWhen one class is a friend of another class, it is typical for the classes to reference each other in their class definitions.. ■ REFERENCES A reference is the name of

Trang 1

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

Trang 2

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

2If 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

Trang 3

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 chapparame-ter, 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 destroygenerat-ing 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.

Trang 4

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 R Reeeettttuu urrrrnn u niiiinn n ng n g M g M Meeeem m mb b beeeerrrr V Vaaa V arrrriiiiaaa ab b blllleeeessss ooo offff aaa a CCC Cllllaaa assssssss TTTTyyy yp peeee When returning a member p 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

Trang 5

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 <<

Trang 6

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.

Trang 7

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 extracdefini-tion 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

Trang 8

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 {

9 Money( );

10 Money(double amount);

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);

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";

40 cout << "One of us is richer.\n";

41 Money ourAmount = yourAmount + myAmount;

Trang 9

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;

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 << "$-";

57 outputStream << ’$’;

58 outputStream << absDollars;

59 if (absCents >= 10)

60 outputStream << ’.’ << absCents;

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 != ’$’)

73 cout << "No dollar sign in Money input.\n";

74 exit(1);

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.

Trang 10

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

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