Operator Overloading

Allows operators to work on classes.

 

Just as methods can be overloaded, so too can most of the operators:

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

 

The exceptions being:

Ternary ? : sizeof() Scope Resolution :: Dot member selector . Member pointer selector .*

 

There are two main types of operator overloading:

  • Unary
    • Acting upon a single object
  • Binary
    • Acting on more than one object

Operators are overloaded by use of the keyword operator followed by the operator sign to be overloaded e.g. (operator=) and its new functionality then defined in the code body.

 

We have already seen the assignment = operator being overloaded in the above article on Copy constructor and assignment overloading, and the same principle is applied to overload the other operators.

 

Syntax:

return_type operator sign ( parameters ) {

...code body...

}

 

It should be fairly straight forward to see that a + b, could easily be translated into operator+(a, b). Assuming there are overloaded methods for the + operator, the compiler knows which one to use based on the type of parameters being sent. i.e. two ints or two floats, or two objects.

 

This example creates two simple Book objects consisting of an ISBN number and a price. The + operator has been overloaded to add the price component of the two objects, based on the type of parameter which in this case is a Book object. The overloaded method operates on the first operand (internally the this self reference) and adds the second object (as the passed in parameter):

#include <iostream>
using namespace std;

class Book {

private:
	int isbn ;
	float price ;

public:
	Book(int num, float cost) {
		isbn = num ;
		price = cost ;
	}
	float operator+(Book &id){
		cout << "The address of this is: " << this << endl;
		cout << "The address of the passed in parameter is: " << &id << endl;

		cout << "The price component of this is: " << this->price << endl ;
		cout << "The price component of the current object : " << price << endl ;
		cout << "The price component of the passed in parameter is: " << id.price << endl ;

		return price + id.price ;
	}
} ;

int main() {

	Book CPP(123459876, 15.66);
	Book Perl(67891234, 21.32);

	cout << "The address of CPP is: " << &CPP << endl ;
	cout << "The address of Perl is: " << &Perl << endl ;

	cout << "The total cost of the two books = " << CPP + Perl << endl ;

	return 0 ;
}

Compile & Run:

The address of CPP is: 0x28ff08
The address of Perl is: 0x28ff00
The address of this is: 0x28ff08
The address of the passed in parameter is: 0x28ff00
The price value of this is: 15.66
The price value of this is: 15.66
The price value of the passed in parameter is: 21.32
The total cost of the two books = 36.98

 

This example is overly verbose to show the internals of the objects.

Note, that a reference has been used as the parameter to simplify memory allocation, by referring to the passed in parameter another copy of the passed in object is not required and hence the additional memory overhead associated with that copy is not required. The example would have worked just the same without using a reference, but give it a try and you will see a new address created for the temporary object being created from the passed in parameter.

 

Also note, the operator+ function could have been called like so: CPP.operator+(Perl) however it is far less awkward to simply write + to produce the same result. Again, try it out; replace the addition expression on line 35 with CPP.operator+(Perl) to achieve the same (but not so easily read) result.

 


 

It is also possible to make the +, -, & and * operators act as a unary or a binary operator, depending on context. This example show the - minus sign operator being overload in both unary (line 15, called from lines 39 and 40) and binary (line 22, called from line 45) contexts:

#include <iostream>
using namespace std;

class CoOrd {

private:
	int xPos, yPos, zPos;

public:
	CoOrd(int x, int y, int z) {
		xPos = x ;
		yPos = y ;
		zPos = z ;
	}
	CoOrd operator-(){ //acting as a unary operator
		xPos = -xPos ;
		yPos = -yPos ;
		zPos = -zPos ;
		return CoOrd(xPos, yPos, zPos) ;
	}

	CoOrd operator-(CoOrd & id) { //acting as a binary operator
		xPos = xPos - id.xPos ;
		yPos = yPos - id.yPos ;
		zPos = zPos - id.zPos ;
		return CoOrd(xPos, yPos, zPos) ;
	}

	void showValues(){
		cout << "xPos: " << xPos << ", yPos: " << yPos << ", zPos: " << zPos <<endl ;
	}
} ;

int main() {

	CoOrd Home (12, -34, -63);
	CoOrd Work (-17, 22, 42);

	Home = -Home ;
	Work = -Work ;

	Home.showValues() ;
	Work.showValues() ;

	CoOrd result = Home - Work ;

	result.showValues() ;

	return 0 ;
}

Compile & Run:

xPos: -12, yPos: 34, zPos: 63
xPos: 17, yPos: -22, zPos: -42
xPos: -29, yPos: 56, zPos: 105

Leave a Reply