Introduction
For int, a + b and cout << a just work. For a class of your own, C++ lets you say what they mean by writing functions named operator+, operator==, operator<< and so on. This is operator overloading: a + b becomes a call of operator+.
Operator overloading lets your own types read like built-in ones: vectors added with +, money compared with <, and any object printed with cout <<. Used with care, it makes code shorter and clearer.
How it works
Arithmetic, comparison and printing
#include <iostream>
using namespace std;
class Vec {
int x, y;
public:
Vec(int x, int y) : x(x), y(y) {}
Vec operator+(const Vec& o) const {
return Vec(x + o.x, y + o.y);
}
Vec operator*(int k) const {
return Vec(x * k, y * k);
}
bool operator==(const Vec& o) const {
return x == o.x && y == o.y;
}
friend ostream& operator<<(ostream& out, const Vec& v);
};
ostream& operator<<(ostream& out, const Vec& v) {
out << "(" << v.x << ", " << v.y << ")";
return out;
}
int main() {
Vec a(1, 2), b(3, 4);
Vec c = a + b * 2;
cout << a << " + " << b << " * 2 = " << c << endl;
if (c == Vec(7, 10)) cout << "equal" << endl;
return 0;
}Vec operator+(const Vec& o) constis a member operator: ina + b,ais the object (this) andbis the parametero. It returns a newVec;aandbdo not change. Watch the call stack:a + breally is a call ofVec::operator+.operator==returns abool, soif (a == b)works.operator<<cannot be a member ofVec, because its left side iscout, anostream. It is a free function, declared a friend so it may read the privatexandy. It returns the stream, socout << a << endlkeeps going.
a + b * 2 still follows the usual precedence: overloading changes what an operator does, never how strongly it binds.
Syntax
Vec operator+(const Vec& o) const; // member: a + b
bool operator==(const Vec& o) const; // member: a == b
friend ostream& operator<<(ostream& out, const Vec& v);
int& operator[](int i); // member: x[i]
Example
#include <iostream>
using namespace std;
class Marks {
int data[3];
public:
Marks() {
for (int i = 0; i < 3; i++) data[i] = 0;
}
int& operator[](int i) {
if (i < 0 || i >= 3) {
cout << "bad index " << i << endl;
return data[0];
}
return data[i];
}
};
int main() {
Marks marks;
marks[0] = 80;
marks[1] = 95;
marks[5] = 1;
cout << marks[0] + marks[1] << endl;
return 0;
}operator[] returns int&, a reference to the element, so marks[1] = 95 can change it, not just read it. The class can also check the index, which plain arrays never do.
| Write it as | Operators |
|---|---|
| a member (left side is your object) | = [] += -= ++ --, usually + - == < too |
| a free friend function | << and >> (left side is a stream) |
Line by line
Markskeeps three ints in a private array, and its constructor sets them to 0.operator[]checks the index. A bad index prints a message and returnsdata[0]so that the program can carry on.- A good index returns
data[i]by reference, so the caller can change it. marks[0] = 80;andmarks[1] = 95;store values through the returned references.marks[5] = 1;is caught: the messagebad index 5is printed, and 1 goes intodata[0].- The last line adds
marks[0]andmarks[1], which are now 1 and 95, and prints 96.
Expected result
bad index 5
96
In the real world
The standard library uses overloading everywhere: + joins strings, << prints, [] indexes vectors and maps, and < lets sort order your objects. Maths libraries for vectors, matrices and big numbers depend on it so that formulas look like formulas.
Common mistakes
- Changing an operand in
operator+:a + bshould not changea. Useoperator+=for that. - Returning the stream by value from
operator<<: returnostream&, so chains work. - Overloading an operator to mean something surprising (
-that adds): others will misread your code.
Best practices
- Overload an operator only when its meaning is obvious.
- Implement
+using+=, so the two always agree. - Pass operands by
const&, and mark operators that do not change the object as const.
Summary
Operators on class types are calls of functions such as operator+ and operator<<. Members suit operators whose left side is your object, friends suit << and >>, and operator[] returns a reference so that it can be assigned to.
Quick check
Key takeaways
- a + b with a class type is a call of operator+.
- operator<< is a free function that returns the stream.
- operator[] returns a reference so that the result can be assigned to.
- Overloading changes what an operator does, never its precedence.
Practice problems for this lesson
My notes
Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.