Operator overloading is heavily used in math. One of the most famous examples I know is “+”. If you add two elements from $$\mathbb{N}$$ you will use the same character “+” as you use for adding two numbers from $$\mathbb{R}$$. You even use the plus-sign if you add matrices (which is obviously something different than adding single numbers).

In some programming languages, like C++, you can overload operators by yourself.

## First simple example

Imagine you wanted to store some data – lets say the prename, surname and age – about people you know. This could be done in a struct. After you’ve stored it, you would like to print this information. Obviously, you don’t want to do something like this:

for (int i=0; i< 4; i++) {
cout << "Person(" << myArray[i].prename << " "
<< myArray[i].surname << ", " << myArray[i].age << ")";
}


If you wanted to print this information more than one time, you would have to add this long line every time.

A toString() method like the one Java uses would be nice. In C++, you don’t have toString, but you can overload the << operator!

This is how it works:

#include <iostream>

using namespace std;

typedef struct person {
// attributes
string prename;
string surname;
int age;

// constructor
person(string p, string s, int age) :
prename(p), surname(s), age(age) {}
} Person;

// "toString" for C++
std::ostream& operator<<(std::ostream &strm, const person &a) {
return strm << "Person(" << a.prename << " " << a.surname << ", "
<< a.age << ")";
}

int main(){
Person Martin ("Martin", "Thoma", 22);
Person Andreas ("Andreas", "Thoma", 22);
Person AndiOld ("Andreas", "Berger", 30);
Person AndiYoung ("Andreas", "Berger", 22);

Person myArray[] = {Martin, Andreas, AndiOld, AndiYoung};

for (int i=0; i< 4; i++) {
cout << myArray[i] << endl;
}

return 0;
}

## Sorting

You can sort by overloading <.
You can use a sort by adding

#include <algorithm>

to your program and using sort(array, array + elements);

This is how it looks like:

#include <iostream>
#include <algorithm>

using namespace std;

typedef struct person {
// attributes
string prename;
string surname;
int age;

// constructor
person(string p, string s, int age) :
prename(p), surname(s), age(age) {}
} Person;

// ".equals()" for C++
bool operator<(const Person& a, const Person& b){
if (!(a.prename == b.prename)) {
return a.prename < b.prename;
} else if (!(a.surname < b.surname)) {
return a.surname < b.surname;
} else {
return a.age < b.age;
}
}

// "toString" for C++
std::ostream& operator<<(std::ostream &strm, const person &a) {
return strm << "Person(" << a.prename << " " << a.surname << ", "
<< a.age << ")";
}

int main(){
Person Martin ("Martin", "Thoma", 22);
Person Andreas ("Andreas", "Thoma", 22);
Person AndiOld ("Andreas", "Berger", 30);
Person AndiYoung ("Andreas", "Berger", 22);

Person myArray[] = {Martin, Andreas, AndiOld, AndiYoung};

sort(myArray, myArray + 4);

for (int i=0; i< 4; i++) {
cout << myArray[i] << endl;
}

return 0;
}

By the way, if you don’t define < you get something like this:

In file included from /usr/include/c++/4.4/algorithm:62,
from operators.cpp:2:
/usr/include/c++/4.4/bits/stl_algo.h: In function ‘const _Tp& std::__median(const _Tp&, const _Tp&, const _Tp&) [with _Tp = person]’:
/usr/include/c++/4.4/bits/stl_algo.h:2268:   instantiated from ‘void std::__introsort_loop(_RandomAccessIterator, _RandomAccessIterator, _Size) [with _RandomAccessIterator = Person*, _Size = int]’
/usr/include/c++/4.4/bits/stl_algo.h:5220:   instantiated from ‘void std::sort(_RAIter, _RAIter) [with _RAIter = Person*]’
operators.cpp:34:   instantiated from here
/usr/include/c++/4.4/bits/stl_algo.h:89: error: no match for ‘operator<’ in ‘__a < __b’
/usr/include/c++/4.4/bits/stl_algo.h:90: error: no match for ‘operator<’ in ‘__b < __c’
/usr/include/c++/4.4/bits/stl_algo.h:92: error: no match for ‘operator<’ in ‘__a < __c’
/usr/include/c++/4.4/bits/stl_algo.h:96: error: no match for ‘operator<’ in ‘__a < __c’
/usr/include/c++/4.4/bits/stl_algo.h:98: error: no match for ‘operator<’ in ‘__b < __c’
/usr/include/c++/4.4/bits/stl_algo.h: In function ‘_RandomAccessIterator std::__unguarded_partition(_RandomAccessIterator, _RandomAccessIterator, _Tp) [with _RandomAccessIterator = Person*, _Tp = person]’:
/usr/include/c++/4.4/bits/stl_algo.h:2268:   instantiated from ‘void std::__introsort_loop(_RandomAccessIterator, _RandomAccessIterator, _Size) [with _RandomAccessIterator = Person*, _Size = int]’
/usr/include/c++/4.4/bits/stl_algo.h:5220:   instantiated from ‘void std::sort(_RAIter, _RAIter) [with _RAIter = Person*]’
operators.cpp:34:   instantiated from here
/usr/include/c++/4.4/bits/stl_algo.h:2209: error: no match for ‘operator<’ in ‘* __first < __pivot’
/usr/include/c++/4.4/bits/stl_algo.h:2212: error: no match for ‘operator<’ in ‘__pivot < * __last’
/usr/include/c++/4.4/bits/stl_algo.h: In function ‘void std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = Person*]’:
/usr/include/c++/4.4/bits/stl_algo.h:2178:   instantiated from ‘void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = Person*]’
/usr/include/c++/4.4/bits/stl_algo.h:5222:   instantiated from ‘void std::sort(_RAIter, _RAIter) [with _RAIter = Person*]’
operators.cpp:34:   instantiated from here
/usr/include/c++/4.4/bits/stl_algo.h:2106: error: no match for ‘operator<’ in ‘__val < * __first’
/usr/include/c++/4.4/bits/stl_algo.h: In function ‘void std::__heap_select(_RandomAccessIterator, _RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = Person*]’:
/usr/include/c++/4.4/bits/stl_algo.h:5067:   instantiated from ‘void std::partial_sort(_RAIter, _RAIter, _RAIter) [with _RAIter = Person*]’
/usr/include/c++/4.4/bits/stl_algo.h:2256:   instantiated from ‘void std::__introsort_loop(_RandomAccessIterator, _RandomAccessIterator, _Size) [with _RandomAccessIterator = Person*, _Size = int]’
/usr/include/c++/4.4/bits/stl_algo.h:5220:   instantiated from ‘void std::sort(_RAIter, _RAIter) [with _RAIter = Person*]’
operators.cpp:34:   instantiated from here
/usr/include/c++/4.4/bits/stl_algo.h:1906: error: no match for ‘operator<’ in ‘* __i < * __first’
/usr/include/c++/4.4/bits/stl_algo.h: In function ‘void std::__unguarded_linear_insert(_RandomAccessIterator, _Tp) [with _RandomAccessIterator = Person*, _Tp = person]’:
/usr/include/c++/4.4/bits/stl_algo.h:2112:   instantiated from ‘void std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = Person*]’
/usr/include/c++/4.4/bits/stl_algo.h:2178:   instantiated from ‘void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = Person*]’
/usr/include/c++/4.4/bits/stl_algo.h:5222:   instantiated from ‘void std::sort(_RAIter, _RAIter) [with _RAIter = Person*]’
operators.cpp:34:   instantiated from here
/usr/include/c++/4.4/bits/stl_algo.h:2067: error: no match for ‘operator<’ in ‘__val < * __next’
In file included from /usr/include/c++/4.4/bits/stl_algo.h:62,
from /usr/include/c++/4.4/algorithm:62,
from operators.cpp:2:
/usr/include/c++/4.4/bits/stl_heap.h: In function ‘void std::__adjust_heap(_RandomAccessIterator, _Distance, _Distance, _Tp) [with _RandomAccessIterator = Person*, _Distance = int, _Tp = person]’:
/usr/include/c++/4.4/bits/stl_heap.h:394:   instantiated from ‘void std::make_heap(_RAIter, _RAIter) [with _RAIter = Person*]’
/usr/include/c++/4.4/bits/stl_algo.h:1904:   instantiated from ‘void std::__heap_select(_RandomAccessIterator, _RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = Person*]’
/usr/include/c++/4.4/bits/stl_algo.h:5067:   instantiated from ‘void std::partial_sort(_RAIter, _RAIter, _RAIter) [with _RAIter = Person*]’
/usr/include/c++/4.4/bits/stl_algo.h:2256:   instantiated from ‘void std::__introsort_loop(_RandomAccessIterator, _RandomAccessIterator, _Size) [with _RandomAccessIterator = Person*, _Size = int]’
/usr/include/c++/4.4/bits/stl_algo.h:5220:   instantiated from ‘void std::sort(_RAIter, _RAIter) [with _RAIter = Person*]’
operators.cpp:34:   instantiated from here
/usr/include/c++/4.4/bits/stl_heap.h:232: error: no match for ‘operator<’ in ‘*(__first + ((unsigned int)(((unsigned int)__secondChild) * 12u))) < *(__first + ((((unsigned int)__secondChild) + 0xffffffffffffffffffffffffffffffffu) * 12u))’
/usr/include/c++/4.4/bits/stl_heap.h: In function ‘void std::__push_heap(_RandomAccessIterator, _Distance, _Distance, _Tp) [with _RandomAccessIterator = Person*, _Distance = int, _Tp = person]’:
/usr/include/c++/4.4/bits/stl_heap.h:244:   instantiated from ‘void std::__adjust_heap(_RandomAccessIterator, _Distance, _Distance, _Tp) [with _RandomAccessIterator = Person*, _Distance = int, _Tp = person]’
/usr/include/c++/4.4/bits/stl_heap.h:394:   instantiated from ‘void std::make_heap(_RAIter, _RAIter) [with _RAIter = Person*]’
/usr/include/c++/4.4/bits/stl_algo.h:1904:   instantiated from ‘void std::__heap_select(_RandomAccessIterator, _RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = Person*]’
/usr/include/c++/4.4/bits/stl_algo.h:5067:   instantiated from ‘void std::partial_sort(_RAIter, _RAIter, _RAIter) [with _RAIter = Person*]’
/usr/include/c++/4.4/bits/stl_algo.h:2256:   instantiated from ‘void std::__introsort_loop(_RandomAccessIterator, _RandomAccessIterator, _Size) [with _RandomAccessIterator = Person*, _Size = int]’
/usr/include/c++/4.4/bits/stl_algo.h:5220:   instantiated from ‘void std::sort(_RAIter, _RAIter) [with _RAIter = Person*]’
operators.cpp:34:   instantiated from here
/usr/include/c++/4.4/bits/stl_heap.h:134: error: no match for ‘operator<’ in ‘*(__first + ((unsigned int)(((unsigned int)__parent) * 12u))) < __value’

## Equality

You can also define == for your structs.

I know this example does NOT make any sense. But it is an example you can work with:

#include <iostream>

using namespace std;

typedef struct person {
// attributes
string prename;
string surname;
int age;

// constructor
person(string p, string s, int age) :
prename(p), surname(s), age(age) {}
} Person;

// "comperator" for C++
bool operator==(const Person& a, const Person& b){
return a.age == 30;
}

int main(){
Person Martin ("Martin", "Thoma", 22);
Person Andreas ("Andreas", "Thoma", 22);
Person AndiOld ("Andreas", "Berger", 30);
Person AndiYoung ("Andreas", "Berger", 22);

Person myArray[] = {Martin, Andreas, AndiOld, AndiYoung};

for (int i=0; i< 4; i++) {
cout << (myArray[i] == myArray[i]) << endl;
}

return 0;
}

## Casting

You can also define casts:

#include <iostream>

using namespace std;

typedef struct person {
// attributes
string prename;
string surname;
int age;

// constructor
person(string p, string s, int age) :
prename(p), surname(s), age(age) {}

// prefix
operator int() { return age; }
} Person;

int main(){
Person Martin ("Martin", "Thoma", 22);
Person Andreas ("Andreas", "Thoma", 22);
Person AndiOld ("Andreas", "Berger", 30);
Person AndiYoung ("Andreas", "Berger", 22);

Person myArray[] = {Martin, Andreas, AndiOld, AndiYoung};

for (int i=0; i< 4; i++) {
cout << int(myArray[i]) << endl;
}

return 0;
}

I like Python very much. Python allows me to get the power of a number like this:

a = 2**10 # 1024

Lets try it for C++:

### Doesn’t work

#include <iostream>

using namespace std;

// does NOT work
// operators.cpp:7: error: expected initializer before ‘*’ token
int operator**(int a, int b){
int power = 1;
for (int i=0; i < b; i++) {
power *= a;
}
return power;
}

int main(){
cout << 2**10 << endl;

return 0;
}

I guess it doesn’t work as it would be very difficult to distinguish something like this:

a = a * *b;
a = a ** b;

If you try to use a $ you get: operators.cpp:16:13: error: invalid suffix "$10" on integer constant

If you try to use a § you get:

operators.cpp:7: error: stray ‘\302’ in program
operators.cpp:7: error: stray ‘\247’ in program
operators.cpp:16: error: stray ‘\302’ in program
operators.cpp:16: error: stray ‘\247’ in program
operators.cpp:7: error: expected type-specifier before ‘(’ token

You are also not allowed to redefine *:

operators.cpp:7: error: ‘int operator*(int, int)’ must have an argument of class or enumerated type

### Works

You can wrap the integer like this:

#include <iostream>

using namespace std;

typedef struct integer {
int inner;

// constructor
integer(int i) : inner(i) {}
} Integer;

int operator^(Integer a, Integer b){
int power = 1;
for (int i=0; i < b.inner; i++) {
power *= a.inner;
}
return power;
}

int main(){
cout << (Integer(2)^Integer(10)) << endl; // outputs 1024
return 0;
}