operator overloading version 1 0
Download
Skip this Video
Download Presentation
Operator Overloading Version 1.0

Loading in 2 Seconds...

play fullscreen
1 / 53

Operator Overloading Version 1.0 - PowerPoint PPT Presentation


  • 78 Views
  • Uploaded on

Operator Overloading Version 1.0. Objectives. At the end of this lesson, students should be able to: Write programs that correctly overload operators Describe how to overload a unary operator Tell how the compiler differentiates between pre- and post

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about ' Operator Overloading Version 1.0' - garan


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
objectives
Objectives

At the end of this lesson, students should be able to:

Write programs that correctly overload operators

Describe how to overload a unary operator

Tell how the compiler differentiates between pre- and post

Describe how to overload a binary operator

Explain when to use member vs non-member functions

Explain when it is necessary to use friend functions

Demonstrate how to return values when overloading operators

Explain why operator overloading is useful

Explain what the compiler generates when it sees an

overloaded operator

Demonstrate how constructors and overloaded cast operator

are used to do conversions

operator overloading
Operator Overloading

In C++, operators are nothing more than functions,

written with a different, but more familiar syntax.

slide4

We use operators to express fundamental

operations in a concise and readable way.

For example,

y = x + y *z;

is much easier to read and write than

y.assign (x.add (y.multiply(z)));

slide5

The standard operators in C++ work on

all of the basic data types. However, they

do not work on user defined data types.

To add two objects of the Length class, we

could write a function called add, so we

could write

lengthThree = lengthTwo.add (lengthOne);

But, this is awkward. Wouldn’t it be nicer

to be able to write

lengthThree = lengthTwo + lengthOne;

slide6

We can do this if we overload the + operator

so that it works with objects of the Length class.

slide8

Define the Length class as …

class Length

{

public:

Length( );

private:

int feet;

int inches;

};

The Length class keeps track of a length

measurement in feet and inches.

slide9

To overload the + operator so that we can add

two Length objects together, we write a function

of the form:

Length operator+ (const Length&);

the name of the function

is operator+

in this case the function

returns a Length object.

the function takes

a const reference to

a Length object as

a parameter.

slide10

Now, if we write

lengthThree = LengthTwo + LengthOne;

The compiler looks in the Length class for a

function with the prototype

Length ::operator+ (const Length&);

slide11

LengthThree = lengthTwo + lengthOne

and generates code just as if we had written

lengthThree = lengthTwo.operator+ (lengthOne);

the left hand operand

becomes the calling

object.

the right hand operand

becomes the parameter

in the function call.

slide12

All of the C++ operators can be overloaded

except for the following:

. .* :: ?: sizeof

Because of the complexities involved, the

overloading of &&, ||, and the comma operator

is discouraged.

key points to remember
Key points to remember

You cannot change the precedence rule

by overloading operators.

You cannot change the associativity of an

operator by overloading it.

It is not possible to create new operators.

You cannot change the way that the operators

work on the basic data types.

You cannot change the “arity” of an operator

by overloading it.

overloading unary functions
Overloading Unary Functions

It certainly ought to be possible to overload

the increment and decrement operators for

the Length class.

For example, we would probably like to be able

to do the following for a length object lengthOne:

lengthOne++;

the makes sense rule
The “makes sense” Rule

A programmer can clearly define what to do

inside of the function that overloads an

operator. However, it is just good programming

practice to be sure that the function makes good

sense.

slide16

So …

what does it mean to increment a Length?

slide17

Let’s choose the option of adding one inch

to the current Length value.

This points out a complexity that we may not have

thought of before. Suppose we have a Length

object whose value is 3 feet and 11 inches. What

happens when we increment this object.

Obviously we want the result to be 4 feet. This

complicates the code we would write, because we

always have to check to see if the addition of one inch

results in going to a new number of feet.

slide18

Let’s simplify the problem by re-defining the Length

class and take advantage of data hiding.

class Length

{

public:

Length( );

private:

int inches;

};

Because we only keep track of inches,

we don’t have to worry here (or in any other

arithmetic operation) about handling the

overflow from inches to feet.

slide19

Now the code for the operator++ function

would look something like:

const Length& Length::operator++( )

{

++inches;

return *this;

}

when written as a member

function, functions that overload

unary operators take no parameters.

the function works on the calling

object. In this case, the inches

data member of the calling object

is incremented.

we return the calling

object (by reference).

return types

in this case, the result of incrementing

lengthOne is used as the right hand

operand for the assignment operator.

So, the increment operator must return

a Length object.

Return Types

In the increment example, why did we return

a Length object, and why by reference?

We pass by reference

for efficiency!

In any expression, the result of some operation may

be used as an operand for another operator. Consider

the expression

cout << ++lengthOne;

more complications
More Complications!

There are a couple of other issues to consider

in this case.

1. How do we differentiate between a pre- and

a post-increment?

2. Should we write the operator++ function as

member function or as a non-member function?

pre or post increment
pre- or post-increment

The code we just examined is for the pre-increment

operator.

To tell the compiler that we want the function to be

for the post-increment operator, we put a dummy

parameter in the function prototype, as :

Length operator++ ( int );

this parameter is never actually

used. It is simply a flag to the

compiler that this function is

overloading the post-increment

operator.

slide23

Length Length::operator++ (int)

{

Length tl = *this;

++inches;

return tl;

}

What’s going on here???

Why is the return different

slide24

the compiler invokes

the operator++(int)

function

Length Length::operator++ (int)

{

Length tl = *this;

++inches;

return tl;

}

inches

5

Length object tl

is local to the

function

myLength++;

inches

5

6

calling object,

myLength

a copy of the object tl is put

on the stack and returned to

the calling program. Why can’t

we return a reference here?

slide25

cout << myLength++;

the result is that the copy of the original

object (with the original value of inches)

is sent to cout.

But, the inches value of myLength

is equal to 6. The effect is that myLength

gets incremented after (post-increment)

the << operator is executed.

member vs non member
Member vs. Non-member

When overloading ( ), [ ], ->, or any of the assignment

operators, the overloading operator function must be

written as a member function.

For all other operators, we may write the function as a

member or a non-member function – your choice.

If the lefthand operand is a basic data type, or an object

of a different class than the operator’s class, then the

operator overloading function must be a non-member

function.

Non-member functions can be written as friend

functions.

friends
Friends

Friend functions are non-member functions

that have all of the privileges of member

functions. In particular, a friend function can

access private data in the class that it is a

friend of.

slide28

Friendship must be given!

class Length

{

public:

Length( );

friend Length& operator++ (Length& t);

private:

int inches;

};

the keyword friend tells

the compiler that the function

operator++ is a friend of the

class. It is a non-member function.

The function has access to the

private data inches.

slide29

because it is a non-member

function, we must pass the

object to be worked on as

a parameter.

the function goes in a .cpp file.

Note that there is no scope

resolution operator nor a class

name because the function does

not belong to the class.

Length operator++ (Length& t)

{

t.inches++;

return t;

}

the code inside the function

can directly access the inches

data member, even though it

is private.

don’t include the keyword friend

here. The function cannot claim

it is a friend. This is done in the

class definition.

slide30

Object Oriented purists don’t like friend

functions because they break the rules of

encapsulation and data hiding.

If you want to be pure, provide accessor

functions in the class and invoke them

from the non-member function. However,

this is less efficient than using a friend

function.

friend classes
Friend Classes

A class can be a friend of another class.

When a class is declared as a friend, all

of its member functions can access the

private data of the class it is a friend of.

overloading binary operators
Overloading Binary Operators

A binary operator takes two operands.

We will refer to these as the left-hand

operand and the right-hand operand.

operator

a = b + c;

right-hand

operand

left-hand

operand

as a member function
As a Member Function

functions that overload binary

operators, written as member

functions, take one parameter,

the right-hand operand.

the result of adding

two Length objects

ought to be a Length

object.

Length Length::operator+ (const Length& rh)

{

Length tLen;

tLen.inches = inches + rh.inches;

return tLen;

}

this value comes from the

calling, or implicit object,

the left-hand operand.

slide34

for a, b, and c all

Length objects …

operator

a = b + c;

b. operator+ (c);

The compiler generates

the function invocation …

right-hand

operand

left-hand

operand

nameless temporary objects

the operator+ function is called

to evaluate the right hand side

of the equation.

Nameless Temporary Objects

In the evaluation of the expression

a = b + c;

finally the assignment is

done. By default, each

data member of the nto

is copied into the corresponding

data member of the object a.

a Length object is returned

on the stack. This object has

no name, and is oftentimes

called a nameless temporary

object (nto).

after completing the

assignment, the nto is

removed from the stack

and no longer exists.

commutative operators
Commutative Operators

+ is a commutative operator. That is,

b + c;

is the same as

c + b;

slide37

But what if one operand is a basic data

type, for example, an integer. This probably

makes sense, since, for example, we can think

of adding an integer, like 5, to a Length.

To make the operator commutative, we should

be able to write

Length c = myLength +5;

as well as

Length c = 5 + myLength;

but … how do we write the function in

this case?

slide38

Rule of thumb:

If the piece of data that you would normally

send the message to (the left-hand operand)

is a basic data type, then you have to overload

the operator by writing a non-member function!

as a non member function
As a Non-member Function!

functions that overload binary operators

take two operands when written as a non-

member function.

Length operator+ ( int lh, const Length& rh)

{

Length tLength;

tLength.inches = lh + rh.inches;

return tLength;

}

overloading and
Overloading << and >>

<< and >> are binary operators where the

left-hand operator is always of a different class

than the one for which we are overloading the

operator. For example,

cout << myLength;

so .. we must write these as non-member

functions.

slide41

Because we want to represent a Length as

feet and inches externally, we must do some

conversions. As a result, the function to overload

the << operator might look like:

out must be passed

by reference because the

ostream class has no

copy constructor.

ostream &operator<< (ostream &out, const Length &rh)

{

int ft = rh.inches/12;

int in = rh.inches %12;

out << ft << “ft., “ << in << “in”;

return out;

}

convert inches to

feet and inches.

the stream is returned so that

we can cascade the << operator.

cascading
Cascading <<

out << ft << “ft., “ << in << “in”;

this expression is evaluated first, and returns the stream out.

The entire expression may now be thought of as

out << “ft., “ << in << “in”;

where out already contains

5

out

slide43

out << “ft., “ << in << “in”;

this expression is evaluated next, and returns the stream out.

The entire expression may now be thought of as

out << in << “in”;

where out already contains

5 ft.

out

slide44

out << in << “in”;

this expression is evaluated next, and returns the stream out.

The entire expression may now be thought of as

out << “in”;

where out already contains

5 ft. 3

out

slide45

out << “in”;

finally this expression is evaluated and returns the stream out.

The return value is not used in this last instance.

out now contains

5 ft. 3 in.

out

stream extraction
Stream Extraction

Overloading the Stream Extraction operator is

similar. Here, we have to decide how the user

will enter in the length.

In this example, I have assumed that the user

will enter the number of feet, followed by white

space, and then the number of inches (I would

probably prompt the user to enter the data

this way).

slide47

istream &operator>> (istream &input, Length &rh)

{

int ft, in;

input >> ft;

input >> in;

rh.inches = in + 12 * ft;

return input;

}

conversions and overloading
Conversions and Overloading

When converting from a basic data type to a

user defined class, the compiler looks for

a constructor in the class that takes the base

data type as a parameter.

Length::Length (const float r)

{

inches = r * 12;

}

slide49

Now, if the programmer writes

myLength = 5.3;

the compiler invokes the constructor to

create a nameless temporary object (nto). The

assignment from the nto to the object myLength

is then performed and the nto is thrown away.

Note: 5.3 is in feet!

slide50

When converting from a user defined class to

a base data type, the compiler looks for a

function that overloads the cast operator.

Length::operator float( )

{

int ft, in;

ft = inches/12;

in = inches %12;

float r = (float)in/12.0;

return ft + r;

}

notice that no return type

is declared. The return type

is derived from the type of

cast being done.

slide51

Now if the programmer writes

float r = myLength;

The compiler invokes the function written

to overload the cast operator to do the conversion.

slide52

When converting from an object of one class

to an object of another class, an explicit cast

is not always required. A statement like

orangeObject = appleObject;

will cause the compiler to look for a constructor

in the Orange class that takes an Apple object

as a parameter, or a function in the Apple class

that overloads the cast operator to return an

Orange object.

slide53

If both a constructor and a cast operator

are defined, the compiler will give an

ambiguity error. It does not know which

you want it to use.

ad