Home CPSC 340

Operator Overloading

Motivation

The point of object-oriented programming is to create new types. When we create types, we want to be able to use them as naturally as possible. Suppose we have written a Fraction class to represent fractional values:


Fraction a(1, 2);   //  1/2
Fraction b(1, 3);   //  1/3
If we want to add these fractions together, we could do so with a free function or a member function:

Fraction sum = addFractions(a, b);
Fraction sum = a.addFraction(b);
However, it would be quite nice to be able to add them with the standard + operator like so:

Fraction sum = a + b;
By default, of course, the compiler will not know how to add these objects together. With operator overloading, we can tell the compiler how to add new objects together and allow us to use our new types more naturally.


Fundamentals

An operator overload in C++ is just a regular function. Like any function it has a return type, a parameter list, and a name. The name of an overloaded function is the word "operator" followed by the operator in question. For example an overload of the addition operator is a function called "operator+".

There are a few rules when overloading operators:

Most operator functions can be written as member functions, or as free functions. They can return any data type.


Overloading Binary Operators as Member Functions

When overloading an operator as a member function, the left hand side of the operation is the object that the class represents. The right hand side of the operation is another object of the same class that is passed as a parameter. This is illustrated below where the values in brackets should be replaced:

class [Name] {

  [return-type] operator[symbol](const Name& other) {


  }
};
When the operator is called, the left hand side is the object itself, and the right hand side is passed as the parameter. This example shows how we could overload addition for fractions using a member function.

Overloading Binary Operators as Free Functions

We can also overload an operator as a free function that isn't part of any class. When doing this, the operator function takes two parameters - one for each side of the operation. This is illustrated below:

class [Name] {
  // ...
};

[return-type] operator[symbol](const Name& left, const Name& right) {

}

When the operator is called, the left hand side is the first parameter and the right hand side is the second.

This example shows how we could overload addition for fractions using a free function.


Overloading Comparison Operators

We can also overload the comparison operators (<, <=, >, >=, ==, !=) for comparing objects. The operators should typically return bool values. Like other binary operators, they can be overloaded as member functions or free functions. This example shows how the Fraction class can overload the < operator as a free function.

We can define all six of the comparison operators individually, or we can define the other five using the < operator we already defined. This is illustrated for the fraction class here.


Overloading Unary Operators

Unary operators such as !, - and ~ can be overloaded as well. If they are overloaded as member functions, they take no parameters, and if they're overloaded as free functions, they take one. This example shows how to implement the unary - operator for Fraction objects with a member function.

Overloading Insertion and Extraction Operators

The examples above all use a print() function for displaying the values of the Fraction objects on the screen. It would be nicer if we could print them just like any other values with cout <<. We can do this by overloading the << operator.

The left hand side of the << operator is the cout object which has the class ostream. This means that the first parameter to the operator function must be of type ostream. Because we can't add functions into the ostream class (it's part of the standard library), we can only overload these operators as free functions. The operator also must return the ostream object. This example shows the Fraction class with the << operator.

We can also overload the >> operator to be able to read our objects from cin. The first parameter of this operator is of type istream, and the operator must return the istream as well. This example shows the Fraction class with the >> operator added in as well.

Copyright © 2018 Ian Finlayson | Licensed under a Creative Commons Attribution 4.0 International License.