Learning materials

Operator Overloading

On this page

Syntax

Assumptions: a and b are operands; @ is the placeholder for the operator, not the @ operator

Operator Overloading Syntax

Expression As method As function
@a (a).operator@() operator@(a)
a@b (a).operator@(b) operator@(a, b)
  • Operators that can be overloaded

    + - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= && || ++ -- , ->* ->

Operator overloading as methods

  • Only when a is a class-typed object
  • Declare as a method in the class of the object a
  • Declare as const method to make a const
  • Declare b as a const formal parameter to make b
class Point {
  int x;
  int y;
 public:
  Point()=default;
  Point(int x, int y): x(x), y(y) {}
  Point operator+(const Point& other) const {
    return Point(x + other.x, y + other.y);
  }
  // binary - operator
  Point operator-(const Point& other) const {
    return Point(x - other.x, y - other.y);
  }
  // Unary - operator
  Point operator-() const {
    return Point(-x, -y);
  }
  // better to make it const! Check the warning after
  bool operator==(const Point& other) const {
    return x == other.x && y == other.y;
  }
  void print() const {
    cout << "X: " << x << " Y: " << y << endl;
  }
};

int main() {
  Point p1(10, 5), p2(2, 1);
  Point p3 = p1 + p2;
  Point p4 = p1 - p2;
  p3.print();
  (-p3).print();
  p4.print();
  if (p1 == p2) cout << "P1 equals P2" << endl;
  else cout << "P1 not equal P2" << endl;
  return EXIT_SUCCESS;
}

Operator overloading as functions

  • a and b can be any type
  • Declare a and b as a const formal parameters to make them const
  • may be declared as a friend function of a class to access private instance variables
class Point {
  int x;
  int y;
 public:
  Point()=default;
  Point(int x, int y): x(x), y(y) {}
  void print() const {
    cout << "X: " << x << " Y: " << y << endl;
  }
  // binary +
  friend Point operator+(const Point& p1, const Point & p2) {
    // will need public getter for x and y if not defined as a friend method
    // return Point(p1.getX() + p2.getX(), p1.getY(), p2.getY()
    return Point(p1.x + p2.x, p1.y + p2.y);
  }
  // binary -
  friend Point operator-(const Point& p1, const Point & p2) {
    return Point(p1.x - p2.x, p1.y - p2.y);
  }
  // Unary - operator
  friend Point operator-(const Point &p1) {
    return Point(-p1.x, -p1.y);
  }
  friend bool operator==(const Point& p1, const Point & p2) {
    return p1.x == p2.x && p1.y == p2.y;
  }
};

int main() {
  Point p1(10, 5), p2(2, 1);
  Point p3 = p1 + p2;
  Point p4 = p1 - p2;
  p3.print();
  (-p3).print();
  p4.print();
  if (p1 == p2) cout << "P1 equals P2" << endl;
  else cout << "P1 not equal P2" << endl;
  return EXIT_SUCCESS;
}

Const

It is a great practice to make everything const if possible. For instance, operators like arithmetic, relational, logical operators can usually be made const. Some operators like ++/--, =, +=, etc. cannot be const as they must modify the internal state of the object.

Best Practice

Do not abuse operator overloading. Only use it when it is logically making sense. Anything that may surprise the user should be avoided.