C++ Programming: Operator Overloading

Ashish Bailkeri - Oct 23 '21 - - Dev Community

Operator overloading is one of the special features in C++ programming. The advantages of this feature is that it allows us to apply operators that logically make sense on our custom data structures. Let's how they can be used in real world applications.

Looking at the first use of operator overloading, we can see it in std::cout using the operator << that is overloaded to print values to our terminal. It is used as the following:

int main() {
  std::cout << "Hello, World!\n";
  //        ^^ <-- This is the overloaded operator
}
Enter fullscreen mode Exit fullscreen mode

This is trivial, right? Most of us use it without giving it much thought, but it is important enough that overloading this operator for your own class allows std::cout to print user-defined classes.

A real world example

class CustomVector {
  float x;
  float y;
public:
  explicit CustomVector(float x, float y) : x(x), y(y) {}

  bool operator==(const CustomVector &vec) const {
    return this->x == vec.x && this->y == vec.y;
  }

  CustomVector operator+(const CustomVector &vec) const {
    return CustomVector(this->x + vec.x, this->y + vec.y);
  }
// ...
};
Enter fullscreen mode Exit fullscreen mode

So let's breakdown what is actually going on here. We have a class called CustomVector and we give it the values of x and y, now what do we do with this? We don't want to continuously compare the their x values all the time, so what we do instead is create on operator overload for the == operator to do this for us.

Writing operator functions is as simple as writing a normal function with the difference in the function name being operator followed by a valid operator to overload. In fact, C++ will allow you to overload the new and delete keywords too, although this is not generally recommended.

Applying operators and using std::cout

After our implementation of the + operator, we can add this line:

friend std::ostream& operator<<(std::ostream& s, const CustomVector &vec);
Enter fullscreen mode Exit fullscreen mode

If you don't know what friend functions or classes are, they allow functions and classes to access private variables of a given class.

Finally, we can add our implementation:

std::ostream& operator<<(std::ostream& s, const CustomVector &vec) {
  s << "{ x: " << vec.x << ", " << "y: " << vec.y << " }";
  return s;
}
Enter fullscreen mode Exit fullscreen mode

Brief overview of the parameters shows that we take in an instant of the output stream and an instance of our custom class. Not so bad, right?

Checking our results

Now let's test our code to see it work in action:

int main() {
  CustomVector vec = CustomVector(1.0f, 1.0f);
  CustomVector vec2 = CustomVector(2.0f, 2.0f);

  if (vec == vec2) {
    std::cout << "They are equal\n";
  } else {
    std::cout << "They are not equal\n";
  }

  std::cout << "Vec 1: " << vec << "\n";
  std::cout << "Vec 2: " << vec2 << "\n";
  std::cout << "Vec 3: " << vec + vec2 << "\n";

  return 0;
}
Enter fullscreen mode Exit fullscreen mode

This is what you should see when you run your code:
Result
You can play around with this to get a better fell of it here.

Conclusion

Operator overloading can be confusing at times so it is best to take it slow when using this concept. Be sure to use this appropriately as to not write confusing code, and make sure that you allow flexibility in the classes you write. As with many things in C++, it is easy to shoot yourself in the foot when programming, so be careful. I hope you learned something today from this overview :)

. . . . . .