## Chapter 17 - Operator Overloading

## Chapter Goals

- To learn about operator overloading
- To learn the various categories of operators and their uses
- To learn how operator overloading is employed in the standard library
- To be able to implement operators in your own classes
- To learn how to avoid common errors in operator overloading

## 17.1 Operator Overloading

- Convenient shorthand
- More intuitive:

  > `a + b * c`
  > vs.
  > `plus(a, times(b, c))`

- C++ supports a rich set of operators

## 17.1 Operator Overloading

- Programmer may define his/her own
- Powerful and subtle feature of C++
- Advantages:
  - Easier to remember
  - Reuse of existing code
  - Concise description of the task
- Caveat:
  - Lack of context may disguise meaning

## 17.1 Operator Overloading

To define an operator:

- Can't redefine existing behavior
- Can't change precedence, associativity, or arity
- Can't invent new symbols

Overloadable Operators
+ | - | * | / | % | ^ | &
| | ~ | ! | = | < | > | +=
-= | *= | /= | %= | ^= | &= | |=
<< | >> | <<= | >>= | == | != | <=
>= | && | || | ++ | -- | ->* | .
-> | [] | () | new | new[] | delete | delete[]

## 17.1 Operator Functions

- Can be:
  1. Simple (non-member) functions
  2. Member functions
- To name function: precede the operator symbol with `operator`

## 17.1 Operator Functions (cont.)

Syntax 17.2 : Overloading Operator Definition
    return_type operatoroperator_symbol( parameters )
    {
    	 statements
    }
Example: |
    int operator-( Time a, Time b )
    {
     return a.seconds_from( b )
    }
Purpose: | Supply the implementation of an overloaded operator.

## 17.1 Example - Operator Functions

- The difference between two `Time` objects is the number of seconds between them

  >     int operator-( Time a, Time b )
  >     {
  >        return a.seconds_from( b );
  >     }

- Use the `-` operator instead of calling `seconds_from()`:

  >     Time now;
  >     Time morning( 9, 0, 0 );
  >     int seconds_elapsed = now - morning;

- `operator-` is a nonmember function with two parameters

## 17.1 Operator Overloading

Avoid ambiguous behavior:

>     some_return_type operator+(Time a, Time b);

- `Time` objects represent a point in time, not a duration
  - what does 3 P.M. + 3 P.M. mean?

## 17.1 Operator Overloading (cont.)

- Adding seconds to a `Time` does make sense:

  >     Time operator+(Time a, int sec)
  >     {
  >        Time r = a;
  >        r.add_seconds(sec);
  >        return r;
  >     }

Caveat: Units are not implied by the context. Add minutes? Seconds?

- A function named `add_seconds` is clear

## 17.1 Operator Member Functions

Syntax 17.2 : Overloading Operator Member Function Definition
    return_type ClassName::operatoroperator_symbol( parameters )
    {
       statements
    }
Example: |
    Time Time::operator+( int sec )
    {
       Time r = *this;
       r.add_seconds( sec );
       return r;
    }
Purpose: | Supply the implementation of an overloaded operator member function.

## 17.1 Operator Member Functions

- First interpreted as a member function of the left-most operand
- Subsequent arguments are passed to the member function:

  > `Time later = now + 60;`

  becomes

  > `Time later = now.operator+( 60 );`

- E.g., a binary operator has only one argument

## 17.1 Example - Operator Member Functions

The addition operator as a member function of the `Time` class:

>     class Time
>     {
>        ...
>        Time operator+( int sec ) const;
>     };

>     Time Time::operator+( int sec ) const
>     {
>        Time r = *this;  // Copy the implicit parameter
>        r.add_seconds( sec );
>        return r;
>     }

## 17.1 Operator Overloading - member vs. global

- Some operators (e.g., assignment) are required to be members
- Usually programmer has the choice
- Keep in mind:
  1. Non-members have only public access (or, make it a friend)
  2. No implicit conversion for implicit parameters
- Member function is preferable if
  - The left argument is modified (`+=`)
  - The data fields are not easily accessible

## 17.2 Case Study: Fractional Numbers

New type to represent a ratio of 2 integers:

> `Fraction a( 3, 4 ); // Represents 3/4
> Fraction b( 7 ); // Represents 7/1
> `

Fractions should behave as other numbers:

>     Fraction c( 1, 2 );
>        if( a < b )
>           c = b - a;
>        else
>           c = a - b;
>        cout << "Value is " << c << "\n";

## 17.2 Case Study: Fractional Numbers

Should be able to mix w/other numbers:

>     c = a + 3;  // Should mean same as addition of 3/1
>     double x = 2.5 * a;  // Should convert fraction to a double

## 17.2 Case Study: Fractional Numbers - Construction

- `normalize` (fraction.h, line 70):
  - fraction is in lowest terms
  - denominator is not negative
- Default constructor (line 14) sets value to 0
- Constructor (line 20) sets value to t/1
- Constructor (line 27) sets value to t/b, calls `normalize`

## 17.2 Case Study: Fractional Numbers (`fraction.h`)

## 17.2 Case Study: Fractional Numbers (`fraction.cpp`)

(Discussion follows)

## 17.2 Case Study: Fractional Numbers (`fractiontest.cpp`)

## 17.3 Overloading Simple Arithmetic Operators

- `= + - * / %`
- Parameters types need not match

  > `Time Time::operator+( int seconds ) const;`

- Supply behavior that is analogous to the arithmetic operators; intuitive
- E.g. (fraction.cpp, lines 61-67)
  (See next slide)

## 17.3 Simple Arithmetic Operators - Fraction Example

a/b + c/d is defined to be (a*d + c*d)/(b*d)

>     Fraction operator+(const Fraction& left, const Fraction& right)
>     {
>        Fraction result(left.numerator() * right.denominator()
>           + right.numerator() * left.denominator(),
>           left.denominator() * right.denominator());
>        return result;
>     }

The remaining operations are defined similarly

## 17.3 Unary Arithmetic Operators

- `+ - * &` have both binary and unary forms
- To overload unary form, reduce the number of parameters by one
- E.g.:

  >     Fraction operator-(const Fraction& value)
  >     {
  >        Fraction result(-value.numerator(), value.denominator());
  >        return result;
  >     }

- A unary operator defined as a member function takes no arguments (sect. 17.6)

## 17.4 Overloading Comparison Operators

- Similar to the arithmetic operators
- Not supplied automatically
- Typically return a `bool`
- E.g.: `Time`s are equal <=> difference is 0

  >     bool operator==(const Time& a, const Time& b)
  >     {
  >        return a.seconds_from(b) == 0;
  >     }

## 17.4 Overloading Comparison Operators

- E.g., from the `Fraction` class:

  >     bool operator==(const Fraction&amp; left, const Fraction&amp; right)
  >     {
  >        return left.numerator() * right.denominator()
  >           == right.numerator() * left.denominator();
  >     }

  >     bool operator<(const Fraction& left, const Fraction& right)
  >     {
  >        return left.numerator() * right.denominator()
  >           < right.numerator() * left.denominator();
  >     }

## Productivity Hint 17.2

### Define Comparisons in Terms of Each Other

- Write 1 or 2 member functions; equality, and strict inequality
- Define all comparisons in terms of these functions
- E.g.: `Fraction` class (fraction.cpp)
  - A single `compare` method (line 97), returns an `int`
  - All 6 comparison operators (lines 104-132) call `compare`

## Advanced Topic 17.2

### Symmetry and Conversion

- Arithmetic and comparison operators are generally nonmember functions
- No implicit conversions of left operand for member functions:

  Consider `Fraction a;`

  - `( a == 2 )` works fine (given the constructors)
  - `( 2 == a )` will not work if equality is a member function.

## 17.5 Overloading Input `>>` and Output `<<`

- Originally shift operators
- Almost always overloaded for I/O
- Overloaded exactly as the binary arithmetic operators
- Should be non-member functions

## 17.5.1 Stream Output <<

- Output stream class (chptr. 12) provides ability to write a single character
- Stream library provides insertion operator for all built-in types:

  > `ostream& operator<<(ostream& out, double value);`

  Note: the stream itself is returned

- E.g.: Overload output for `Fraction`

  > `

  >     ostream& operator<<( ostream &out, const Fraction &value )
  >     {
  >        out << value.numerator() << "/" << value.denominator();
  >        return out;
  >     }

  > `

## 17.5.2 Stream Input >>

- Stream library provides for all built-in types
- Can be overloaded, much like the output operator
- 2nd parameter is a non-const reference
- E.g.: Input operator for `Time`

## 17.5.2 Stream Input >> (cont.)

> Assume a `Time` is input as 3 separate integers, `9 15 00` to represent 9:15:00 a.m.
> `

>     istream& operator>>(istream& in, Time& a)
>     {
>        int hours;
>        int minutes;
>        int seconds;
>        in >> hours >> minutes >> seconds;
>        a = Time(hours, minutes, seconds);
>        return in;
>     }

> `

## Advanced Topic 17.3

### Peeking at the Input

You may put a single character back into the stream.

E.g.: We want to allow a user to input a `Fraction` as a single integer (`7`), or as an integer, slash, integer (`3/4`)

## Advanced Topic 17.3 (cont.)

>     istream& operator>>(istream& in, Fraction& r)
>     {
>        int t, b;
>        // Read the top
>        in >> t;
>        // If there is a slash, read the next number
>        char c;
>        in >> c;
>        if (c == '/')
>           in >> b;
>        else
>        {
>           in.putback(c);
>           b = 1;
>        }
>        r = Fraction(t, b);
>        return in;
>     }

## 17.6 Overloading Increment and Decrement Operators

- Generally defined as member functions
- Two versions of each:
  1. prefix version: `++x`
  2. postfix version: `x++`
- C++ uses an extra argument to distinguish the postfix form

## 17.6 Overloading Increment and Decrement Operators

- E.g.: Increments for `Fraction`
  Notice:
  - Prefix returns a reference
  - Postfix does more work

>     class Fraction
>     {
>        . . .
>        Fraction& operator++();  // Prefix form
>        Fraction operator++(int unused);  // Postfix form
>        . . .
>     };

## 17.6 Overloading Increment and Decrement Operators (cont.)

>     Fraction& Fraction::operator++()
>     {
>        top += bottom;
>        return *this;
>     }
>     Fraction Fraction::operator++(int unused)
>     {
>        Fraction clone(top, bottom);
>        top += bottom;
>        return clone;
>     }

## 17.6.1 Iterators and Overloaded Operators

- Iterators (Sect. 16.5) can be used just like pointers (Chptr. 10) to process arrays
- Iterators can be used (in varying capacities) on all standard containers
- Operators overloaded for iterators:

  `+` | addition
  `==` | comparison
  `*` | dereference
  `++` | increment (post and pre)

## 17.6.1 Example: Implementing Iterator Operators

Recall `Iterator`, defined on our `List` of strings. We can now overload the standard operators:

>     Iterator& Iterator::operator++(int)
>     {
>        position = position->next;
>        return *this;
>     }

>     string Iterator::operator*() const
>     {
>        assert(position != NULL);
>        return position->data;
>     }

## 17.6.1 Example: Implementing Iterator Operators (cont.)

>     bool Iterator::operator==(const Iterator& b) const
>     {
>        return position == b.position;
>     }

>     bool Iterator::operator!=(const Iterator& b) const
>     {
>        return position != b.position;
>     }

## 17.7 Overloading the Assignment Operators

### The Assignment Operator, `=`

- Must be a member function
- Is automatically generated
  - Member-wise copy
  - Destructor and copy constructor also supplied by compiler
- Desired behavior for many classes
- Explicitly supply if class has outside references

## 17.7.1 Overloading Compound Assignment Operators (`+= *=`, etc.)

- Never supplied automatically
- Use existing arithmetic and assignment operators to define compound operator
- E.g.: `+=` for `Fraction`

>     Fraction& Fraction::operator+=(const Fraction& right)
>     {
>        top = top * right.denominator() + bottom * right.numerator();
>        bottom *= right.denominator();
>        normalize();
>        return *this;
>     }

## 17.8 Overloading Conversion Operators

- Conversion to a user-defined type is handled by constructors

  E.g.: `Fraction` has a constructor that takes a single integer. This is okay:

  > `Fraction a(3,4), b;
  > b = a + 2; // Addition of Fraction and integer`

  The assignment statement becomes

  > `b = a + Fraction(2);
  > // Convert right operand to Fraction, then add`

## 17.8 Overloading Conversion Operators

- Conversion to a user-defined type (cont.):

  If addition is not a member function, then this works too:

  > `b = 2 + a;`

- Use `explicit` keyword to inhibit implicit conversions (coercions)

## 17.8 Overloading Conversion Operators

- Convert from a user-defined type
- An operator must be supplied for each type to convert to
- Definition:
  - Must be a member function
  - Has a type as its name
  - Has no return type
  - Takes no arguments
- May be used implicitly, or called explicitly (cast)

Note: The compiler performs at most one level of user-defined type conversion when matching an overloaded function.

## 17.8 Example - Overloading Conversion Operators

Convert a `Fraction` to a `double`:

> `

>     Fraction::operator double() const
>     {
>        // Convert numerator to double, then do division
>        return static_cast<double>(top) / bottom;
>     }

> `

Can be used:

>     Fraction a(1, 2);
>     double d = 7.0;
>     double halfd = d * a; // a is converted to double to do multiplication
>     cout << "one half seven is " << halfd << "\n";

## 17.8.1 Stream Loops and Conversion Operators

Consider the familiar construct:

> `

>     while( cin >> x )
>        . . .

> `

- The `>>` operator returns `istream&`
- Not a valid boolean expression
- `istream` provides a conversion operator that returns `false` on end of input or on error

## 17.9 Overloading the Subscript Operator

- Often defined on an indexable container (`vector` or `map`)
- Explicit argument is the index
- Result is the value stored at the given position
- Return a reference to the value to get an L-value
- Must be a member function
- operator`[][]` does not exist

## 17.9 Example: Overloading the Subscript Operator

Implementation of a "safe array":

- The subscript operator checks that index is valid
- First (non-const) version returns a reference, an L-value
- The second version is `const`, returns a copy

## 17.9 Example: Overloading the Subscript Operator (cont.)

>     class SafeArray
>     {
>     public:
>        SafeArray(int s);
>        SafeArray(const int v[], int s);
>        int& operator[](int i);
>        int operator[](int i) const;
>        private:
>        int size;
>        int* values;
>     };

>     SafeArray::SafeArray(int s) : size(s), values(new int[size]) {}

## 17.9 Example: Overloading the Subscript Operator (cont.)

>     SafeArray::SafeArray(const int v[], int s) : size(s)
>     {
>        values = new int[size];
>        for (int i = 0; i < size; i++)
>        values[i] = v[i];
>     }

>     int& SafeArray::operator[](int index)
>     {
>        assert((index >= 0) && (index < size));
>        return values[i];
>     }

>     int SafeArray::operator[](int index) const;
>     {
>        assert((index >= 0) && (index < size));
>        return values[i];
>     }

## 17.10 Overloading the Function Call Operator

- Objects can be used as functions (function object)
- Must be defined as a member function
- Can carry (and change) its own data values
- Only operator where the number of arguments is not fixed
- Can be passed where template functions can't
- Used extensively by various generic algorithms in the STL (chptr. 24)

## 17.10 Example: The Function Call Operator

- Simple to write a function that takes no arguments and returns a random number on [1, 100]
- More difficult to write a similar function (no args) that returns a value on [a, b], where a and b aren't known until run time
- A function object makes it simple:

## 17.10 Example: The Function Call Operator

>     class RandomInt
>     {
>     public:
>        RandomInt(int ia, int ib);
>        int operator()();
>     private:
>        int a, b;
>     };

>     RandomInt::RandomInt(int ia, int ib) : a(ia), b(ib) {}

>     int RandomInt::operator()()
>     {
>        return a + rand() % (b - a + 1);
>     }

## 17.10 Example: The Function Call Operator

Declare an instance, then use it as a function:

>     RandomInt a(7, 15); // Return random values from 7 to 15
>     cout << "one random value " << a() << "\n";
>     cout << "and another " << a() << "\n";

## 17.10 Example 2: Variable arguments

>     class RandomInt
>     {
>     public:
>        RandomInt(int ia, int ib);
>        int operator()();
>        int operator()(int nb);
>        int operator()(int na, nb);
>     private:
>        int a, b;
>     };

## 17.10 Example 2: Variable arguments (cont.)

>     RandomInt::RandomInt(int ia, int ib) : a(ia), b(ib) {}

>     int RandomInt::operator()()
>     { return a + rand() % (b - a + 1); }

>     int RandomInt::operator()(int nb)
>     { return a + rand() % (nb - a + 1); }

>     int RandomInt::operator()(int na, int nb)
>     { return na + rand() % (nb - na + 1); }

## 17.10 Example 2: Variable arguments

The function selected will be determined by the number of arguments provided:

>     RandomInt r(3, 7);
>     cout << "random value between 3 and 7 " << r() << "\n";
>     cout << "random value between 3 and 10 " << r(10) << "\n";
>     cout << "random value between 23 and 30 " << r(23, 30) << "\n";

## Advanced Topic 17.5

### Other Operators

Operators not commonly used, hence, not commonly overloaded:

- Comma operator

- Has lower precedence than assignment

- `&`, `|` and `^`
  - `^` has lower precedence than addition.

## Advanced Topic 17.5

### Other Operators (cont.)

- `&&` and `||`
  - Lose their short-circuit logic when overloaded
- `~` and `!`
- `->`
  - Can make smart pointers
- `new` and `delete`

## Advanced Topic 17.6

### Inline Functions

- Avoid overhead of function calls
- Body expanded in place of each call
- Only for very short functions ( <= 3 lines )

To define:

- Precede definition w/ `inline`
- Place in interface file
- Same for member function
- Alternatively, define member function inside class definition

## 17.11 Case Study: Matrices

Operations on matrices:

- Addition
- Scalar multiplication
- Matrix multiplication

- Single row by single column
- Apply above algorithm to all rows of first by all columns in second

## 17.11 Case Study: Matrices

Implementation:

- 2D array:
  - Indices not checked
  - Need helper functions to copy
  - Can't use standard arithmetic operators
- Create `Matrix`:
  - Number of ROWS and COLUMNS variable; can't use a 2D array underneath
  - Use a 1D array. So, elementi,j will be found at

    > `i * COLUMNS + j`

## 17.11 Case Study: Matrices (cont.)

- Subscripting:
  1. Overload function-call operator, OR
  2. Subscript (`[]`) returns `MatrixRow`, which provides its own (`[]`) operator
- We choose option 2
  - const vs. non-const => also provide a `ConstMatrixRow`
- Small functions will be `inline`

## 17.11 Case Study: Matrices (`matrix1.h`)

## 17.11 Case Study: Matrices (`matrix1.cpp`)

Implementation for the `Matrix` class:

## 17.11 Case Study: Matrices (`matrixtest1.cpp`)

## Chapter Summary

1. Define new meanings for C++ operators
2. Member vs. nonmember operators
3. Extend new types using stream I/O operators
4. Simulate pointers by defining operators on iterators
5. Operators to define behavior of conversions
6. Function objects