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
}
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);
}
// ...
};
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);
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;
}
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;
}
This is what you should see when you run your code:
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 :)