Overloading Operators

It would be more convenient to use "==" instead of "equal".

But "==" isn't defined on objects of type money (only

on built-in types).

The compiler wouldn't know what it "means" to ask if

two money objects are the same.  

But you can tell it…

We can overload operators such as ==, +, *, =, and [].

Remember that "overload" means to supply an additional

meaning applicable to different types of data. In this case

we give a new meaning to an operator (like "==") in the

case that the type of data involved is an object of type money.

Here's how:

class Account {

public:

   friend bool operator ==(const Acount& act1,

                                        const Account& act2) const;

   friend Account operator +(const Acount& act1,

                                           const Account& act2) const;

   ...

}

The word "operator" signals to the compiler that an operator

symbol is the function to be overloaded. In other respects it

looks like any other function prototype.

Note that operator == is a friend -- it is not a member of the class!!

Here is the actual body of the code (outside the class):

bool operator == (const Acount& act1,

                           const Account& act2) const

{

          return (act1.balance == act2.balance);

}

Account operator + (const Acount& act1,

                              const Account& act2) const

{

          Account temp;

          temp.balance = act1.balance + act2.balance;

          return temp;

}

Account act1, act2, act3, act4;

...

if (act1 == act2) ...

...

act4 = act1 + act2 + act3;

or

if (operator==(act1,act2)) ..   // name of function is operator==

...

act3 = operator+(act1,act2);   // name of funciton is operator+

 

Some rules:
- you cannot define new operators
- "friend" is not required
- one of the parameters must be of a class type
- you cannot change the number of arguments or the precedence of the operator.


Overloading << and >>

The output (<<) and input (><) and input (>>) operators can also be overloaded.

class Account {

public:

  friend ostream& operator<<(ostream& outs, const Account& act);

  friend istream& operator>>(istream& ins, Account& act);

  ...

}

Account act1;

cin >> act1;

cout << act1;

First, consider insertion operator <<. ><

Notice that the function returns an ostream&, and also takes an

ostream& as a parameter.

Why is the ostream parameter a reference? The output operator will
change the output stream:

 ostream& operator<<(ostream& outs,

                                        const Account& act) const

{

    outs << "The balance is:" << act.balance;

    return outs;

 }

 ...

 cout << act1;

Since cout is changed, parameter outs should be a reference (so outs and
cout refer to the same object.)

Why do we return a reference to an ostream object? Output expressions can
be chained:

  cout << act1 << act2 << act3;     

This is the same as:

  ((cout << act1)  << act2 ) << act3

That is:

          The result of (cout << act1) must be an object into which

we can insert

          The only kind of object into which we can insert is a stream

          Therefore (cout << act1) must return a stream!

          Therefore the operator << must return a stream.

The stream it returns is cout -- i.e. it returns the same stream we

give it.

 ostream& operator<<(ostream& outs,    // we give it outs

                                      const Account& act) const {

    outs << "The balance is:" << act.balance; 

    return outs;      // and it returns the same stream

 }

 ...

 cout << act1;  // cout is the ostream argument

Since we use "ostream&" as the parameter type and the return type:
- parameter outs is another name for argument cout
- the returned object is another name for parameter outs
==> the returned object is another name for argument cout,
       i.e., we return cout.

The extraction operator is overloaded the same way:

class Account {

public:

  friend ostream& operator<<(ostream& outs, const Account& act);

  friend istream& operator>>(istream& ins, Account& act);

  ...

}

//Account act1;

//cin >> act1;

//cout << act1;

istream& operator>>(istream& ins, Account& act) {

    ins >> act.balance;

    return ins;  // return the argument

 }

We return an istream reference since input operations can also be chained:
     cin act1 >> act2 >> act3;

Next: Example Class with Overloading


Slide 6