• Martin Thoma
  • Home
  • Categories
  • Tags
  • Archives
  • Support me

C++ Operator overloading

Contents

  • First simple example
  • Sorting
  • Equality
  • Casting
  • Adding new operators
    • Doesn't work
    • Works
  • See also

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

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;
}

Adding new operators

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 &lsquo;*&rsquo; 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 &lsquo;\302&rsquo; in program
operators.cpp:7: error: stray &lsquo;\247&rsquo; in program
operators.cpp:16: error: stray &lsquo;\302&rsquo; in program
operators.cpp:16: error: stray &lsquo;\247&rsquo; in program
operators.cpp:7: error: expected type-specifier before &lsquo;(&rsquo; token

You are also not allowed to redefine *:

operators.cpp:7: error: &lsquo;int operator*(int, int)&rsquo; 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;
}

See also

  • A class for dealing with fractions - which includes 7 examples for operator overloading
  • Operators in C and C++
  • The General Syntax of operator overloading in C++. sbi, Stack Overflow.
  • The Three Basic Rules of Operator Overloading in C++. sbi, Stack Overflow.
  • Overloading operators. C++-Reference.

Published

Jul 6, 2012
by Martin Thoma

Category

Code

Tags

  • CPP 10

Contact

  • Martin Thoma - A blog about Code, the Web and Cyberculture
  • E-mail subscription
  • RSS-Feed
  • Privacy/Datenschutzerklärung
  • Impressum
  • Powered by Pelican. Theme: Elegant by Talha Mansoor