C++ operator overloading

Give a Vec2 class natural arithmetic, comparison, and output operators.

C++
#include <iostream>

struct Vec2 {
  int x;
  int y;

  Vec2 operator+(const Vec2& other) const { return {x + other.x, y + other.y}; }
  Vec2 operator-(const Vec2& other) const { return {x - other.x, y - other.y}; }
  Vec2 operator*(int k) const { return {x * k, y * k}; }
  bool operator==(const Vec2& other) const { return x == other.x && y == other.y; }
};

std::ostream& operator<<(std::ostream& out, const Vec2& v) {
  return out << "(" << v.x << ", " << v.y << ")";
}

int main() {
  Vec2 a{1, 2};
  Vec2 b{3, 4};
  std::cout << a + b << "\n";
  std::cout << b - a << "\n";
  std::cout << a * 3 << "\n";
  std::cout << (a + b == Vec2{4, 6}) << " " << (a == b) << "\n";
}
Output
(4, 6)
(2, 2)
(3, 6)
1 0

Explanation

Operator overloading lets a user-defined type work with the usual operators. A 2D vector class can define + and - for vectors, * for scaling, == for comparison, and << for printing. Done well, code such as a + b * 2 reads like the mathematics.

Binary arithmetic operators are usually written as const member functions or as free functions that return a new object. The stream operator << must be a free function because its left operand is the stream. Overload only when the meaning is obvious; an operator that surprises its readers is worse than a named function.

Explore the dry run
Guided walkthroughReady
1#include <iostream>
2
3struct Vec2 {
4 int x;
5 int y;
6
7 Vec2 operator+(const Vec2& other) const { return {x + other.x, y + other.y}; }
8 Vec2 operator-(const Vec2& other) const { return {x - other.x, y - other.y}; }
9 Vec2 operator*(int k) const { return {x * k, y * k}; }
10 bool operator==(const Vec2& other) const { return x == other.x && y == other.y; }
11};
12
13std::ostream& operator<<(std::ostream& out, const Vec2& v) {
14 return out << "(" << v.x << ", " << v.y << ")";
15}
16
17int main() {
18 Vec2 a{1, 2};
19 Vec2 b{3, 4};
20 std::cout << a + b << "\n";
21 std::cout << b - a << "\n";
22 std::cout << a * 3 << "\n";
23 std::cout << (a + b == Vec2{4, 6}) << " " << (a == b) << "\n";
24}

Follow the example

Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.

View the complete dry-run table
Prepared trace of the published program. Some rows group repeated iterations.
Step / lineWhat happensState after stepOutput so far
a + b calls a.operator+(b) and returns a new vector. const says that a is not changed.—
—
A free function so that std::cout << v works. It returns the stream so that calls can be chained.—
—
(1,2) + (3,4).—
(4, 6)
(3,4) − (1,2).—
(4, 6)
(2, 2)
Scaling by an int.—
(4, 6)
(2, 2)
(3, 6)
== compares both fields; a bool prints as 1 or 0.—
(4, 6)
(2, 2)
(3, 6)
1 0

Cost and common mistakes

Each operator is O(1).

  • 3 * a does not compile with a member operator*(int), because the left operand is an int. Add a free function for that order.
  • Define == and != together, and keep them consistent. Since C++20, defining == also gives !=, and <=> can generate the comparison operators.
  • Do not overload && or ||, and avoid the comma operator: the overloaded versions lose short-circuit behaviour.

Try it yourself

How do you support 3 * a?

Reveal answer and reasoning

Add a free function Vec2 operator*(int k, const Vec2& v) { return v * k; }.

Further reading