Department of Engineering

IT Services

How not to overload C++ operators

Basics

When you create a new class it's often useful to re-define the operators ("+" for example) so that they work with your new class. Some ways to do this are better than others. This document assumes that you can sometimes learn more from mistakes than perfection. Let's start simply by creating a class that contains only an integer.

// Version 1
#include <iostream>

using namespace std;

class anint {
public:
  int i;
  // 2 constructors
  anint() {
    i=0;
  }
  anint(int a) {
    i=a;
  }
};

int main() {
    anint i(2), j(3), k;
    k=4;
}

In main the objects i and j are created using the constructor that takes one integer. k is created using the constructor that takes no arguments. That "k=4;" works may come as a surprise, but in this situation, C++ uses the constructor that takes one integer to create a temporary aninit that is copied into k. If you don't want C++ to be so liberal, you can put explicit before " anint(int a)".

Adding object to object

One way to add 2 objects of this new class together is to try this

// Version 2
#include <iostream>

using namespace std;

class anint {
public:
  int i;
  // 2 constructors
  anint() {
    i=0;
  }
  anint(int a) {
    i=a;
  }

  anint operator+(const anint& v) {
    anint result;
    result.i = this->i + v.i;
    return result;
  }
};

int main() {
    anint i(2), j(3), k;
    k=i+j;
    cout << "k.i=" << k.i << endl;
}

This works. The new member function is invoked whenever 2 objects of type anint are added. However, if you add

   
  i+j=k;

to main you'll find that the compiler doesn't complain. That's not good news. The fix is to put const at the start of the anint operator+ ... line.

Adding int to object

Suppose that you wanted

  i=j+7;

to compile. It's a reasonable thing to try. If you replace the i+j=k line by i=j+7 it compiles, and produces the right answer (because the 7 is converted to an anint). However, if you replace i=j+7 by i=7+j it fails with an error message something like

 error: no match for 'operator+' in '7 + j'

The problem is that the member function only comes into play when the first operand is of type anint. The parameter of the function describes what type the 2nd operand should be. To cope with the situation where the first operand isn't of type anint, the function has to be outside of the class. Here's some code -

// Version 3
#include <iostream>

using namespace std;

class anint {
public:
  int i;
  // 2 constructors
  anint() {
    i=0;
  }
  anint(int a) {
    i=a;
  }

  const anint operator+(const anint& v) {
    anint result;
    result.i = this->i + v.i;
    return result;
  }
};

// This function adds an int and an anint when the int is first.
const anint operator+(const int& v1,const anint& v2 ) {
    anint result;
    result.i = v1 + v2.i;
    return result;
}

int main() {
    anint i(2), j(3), k;
    k=7+j;
    cout << "k.i=" << k.i << endl;
}

Friends and incrementing

In our anint the integer is public, which isn't a good idea in general. Let's make it private

class anint {
private:
 int i;
public:
  // 2 constructors
  anint() {
  ...

Unfortunately that means that the non-member function operator+ can no longer access the i. We seem to be stuck - whether the function's a member function or not we have problems. Fortunately there are ways out. By making the non-member function a friend of the class, it will have access to all the class members. Here's the code. As a bonus there's a new += function and an output friend function too

// Version 4
#include <iostream>

using namespace std;
class anint {
  friend anint operator+(const int& v1,const anint& v2 );
  friend ostream &operator <<(ostream &stream, const anint v);
private:
  int i;
public:
  // 2 constructors
  anint() {
    i=0;
  }
  anint(int a) {
    i=a;
  }

  const anint operator+(const anint& v) {
    anint result;
    result.i = this->i + v.i;
    return result;
  }

  anint& operator+=(const int& v) {
    this->i+=v;
    return *this;
  }

  // preincrement - faster than postincrement because it doesn't
  // need to create a copy of the original object in order to return it
  anint operator++() {
    ++i;
    return *this;
  }

  anint operator++( int ){
     anint tmp= *this;
     ++i;
     return tmp;
  }

};

// This function adds an int and an anint when the int is first.
const anint operator+(const int& v1,const anint& v2 ) {
    anint result;
    result.i = v1 + v2.i;
    return result;
}

ostream &operator <<(ostream &stream, const anint v) {
    cout << v.i;
    return stream;
};

int main() {
    anint i(2), j(3), k;
    k=7+j;
    cout << "k=" << k << endl;
    k+=2;
    cout << "k=" << k << endl;
    ++k;
    cout << "k=" << k << endl;
}