Understanding Operator Overloading in C++
Published: 2023-08-24 16:04:35

In this article, you will start to understand operator overloading in C++.

### What is it?

**Operator Overloading** can give a special behavior (or meaning) to an operator when it is applied to an instance of a class or a user-defined data type.

### The problem

For example, what happens if we have two instances of a class and we try to add one with another? The compiler in that case doesn't know what to do, then will throw an error.

```cpp

class Color {
public:
    Color(name) 
        : name(name) {}

    std::string name;
};

int main() {
    Color green("Green");
    Color red("Red");

    Color yellow = green + red;
    // error: no match for 'operator+' (operand types are 'Color' and 'Color')
    return 0;
}
```

Have you seen it? We are not able to add the colors because the compiler doesn't know the operator's behavior.

---

Different operators can be overloaded, here are a few:

* Addition: +
    
* Subtraction: -
    
* Multiplication: \*
    
* Division: /
    
* Equality: ==
    
* Addition assignment: +=
    
* Logical AND: &&
    

### How does it work?

Well, let me give you an example.

Do you remember Cell from Dragonball Z? With his Absorption technique, he can absorb an opponent and his strength.

![cell absorbs gif](https://64.media.tumblr.com/e46666874e9458873c69a0a68edc0b2e/tumblr_n7rypyHyef1tu0hbzo4_400.gif align="center")

We can try to replicate the *Cell Absorption* *Technique* in code by overloading the **plus (+)** operator.

```cpp
enum Kind {
    Human,
    Android
};

class Character {
public: 

    Character(string name, Kind kind, float strength)
        : name(name), kind(kind), strength(strength) {}
    
    string name;
    Kind kind;
    float strength;
    bool isAlive{true};
};

int main() {
    return 0;
}
```

In the code above we have an *Enum*, which helps to identify the *Character Kind*,  
and a *Character Class* with its constructor and some member variables.

Now we can write the operator function inside the class

```cpp
Character operator+ (Character& c) {
    if(kind == Kind::Android) {
        c.isAlive = false;
        // Here we simply return a Character, but with the strength addition
        return Character(name, kind, strength + c.strength);
    } else {
        // If the charactor is not an Android, just return it.
        return Character(name, kind, strength);
    }
}
```

---

<div data-node-type="callout">
<div data-node-type="callout-emoji">🧐</div>
<div data-node-type="callout-text">As we can observe, the syntax is the following</div>
</div>

```cpp
return_type operator symbol (arguments) {
    // ....
}
```

---

Let's initialize two characters

```cpp
int main() {
    Character Cell("Cell", Kind::Android, 9000.0);
    // Name: Cell
    // Kind: Android
    // Strength: 9000.0
    // isAlive: true

    Character Krillin("Krillin", Kind::Human, 750.0);
    // Name: Krillin
    // Kind: Human
    // Strength: 750.0
    // isAlive: true
    
    return 0;
}
```

Now Cell can use his technique on Krillin!

```cpp
int main() {
    Character Cell("Cell", Kind::Android, 9000.0);
    Character Krillin("Krillin", Kind::Human, 750.0);

    // Absorption!
    Cell = Cell + Krillin;
    
    Cell.name; // Cell
    Cell.kind; // Android
    Cell.strength; // 9750.0
    Cell.isAlive; // true
    
    Krillin.name; // Krillin
    Krillin.kind; // Human
    Krillin.strength; // 750.0
    Krillin.isAlive; // false

    return 0;
}
```

Pretty straightforward right?  
As you can see, the Cell's strength has increased to 9750.0. This was achieved by "absorbing" Krillin's strength with the help of the overloaded plus operator!

Let's put it all together 👇

```cpp
#include <iostream>
#include <string>
using std::string;

enum Kind {
    Human,
    Android
};

class Character {
public: 

    Character(string name, Kind kind, float strength)
        : name(name), kind(kind), strength(strength) {}
    
    Character operator+ (Character& c) {
        if(kind == Kind::Android) {
            c.isAlive = false;
            // Here we simply return a Character, but with the strength addition
            return Character(name, kind, strength + c.strength);
        } else {
            // If the charactor is not an Android, just return it.
            return Character(name, kind, strength);
        }
    }

    string name;
    Kind kind;
    float strength;
    bool isAlive{true};
};

int main() {
    Character Cell("Cell", Kind::Android, 9000.0);
    Character Krillin("Krillin", Kind::Human, 750.0);

    // Absorption!
    Cell = Cell + Krillin;
    
    Cell.name; // Cell
    Cell.kind; // Android
    Cell.strength; // 9750.0
    Cell.isAlive; // true
    
    Krillin.name; // Krillin
    Krillin.kind; // Human
    Krillin.strength; // 750.0
    Krillin.isAlive; // false
    
    return 0;
}
```

---

### Implementing a Vector2

We can write another more practical example by making a simple implementation of a Vector2, let's do it!

(For those who don't know, a [Vector2](https://www.intmath.com/vectors/3-vectors-2-dimensions.php) defines a position in space)

![](https://i.stack.imgur.com/yYIAm.png align="center")

Here we have a class called **Vector2**

```cpp
class Vector2 {
public:
    Vector2()
        : x(0.0), y(0.0) {}
    
    Vector2(int x, int y)
        : x(x), y(y) {}

    // Vector2 + Vector2
    Vector2 operator+ (Vector2 const& _vec2) {
        return Vec2(x + _vec2.x, y + _vec2.y);
    }
   
    // Vector2 += Vector2
    Vector2& operator+= (Vector2 const& _vec2) {
        x += _vec2.x;
        y += _vec2.y;

        // Return the left-hand Vector2
        return *this;
    }
    
    // Vector2 == Vector2
    bool operator== (Vector2 const& _vec2) {
        if (x == _vec2.x && y == _vec2.y)
            return true;
        else
            return false;
    }

    float x, y;
};
```

Now that we have written the behavior of those operators let's see what happens in the code. Assume that we are making a videogame and there are two Actor:

* AHero
    
* AMonster
    

Those Actors have different positions.

```cpp
// Initialize actors
Vector2D AHero(3.0, 1.0);
Vector2D AMonster(5.0, -3.0);
```

Using the + operator

```cpp
AHero = AHero + Vector2(1.0, 1.0);
// AHero now has a new position

std::cout << AHero.x << " : " << AHero.y << std::endl;
// 4.0 : 5.0
```

Using the += operator

```cpp
AHero += Vector2(3.0, -5.0);
// AHero now has a new position

std::cout << AHero.x << " : " << AHero.y << std::endl;
// 6.0 : -4.0
```

Using the == operator

```cpp
// Initialize actors
Vector2D AHero(3.0, 1.0);
Vector2D AMonster(5.0, -3.0);

// The hero moves
AHero += Vector2(1.0, 1.0); // 4.0, 2.0

// The monster moves to the hero position
AMonster = AMonster + Vector2(-1.0, 5.0);

// Now we check if the two actor are in the same position.
// In this case, the hero dies.
if (AHero == AMonster) {
    // The monster kills the hero.
    // ...    
} else {
    // The hero will live.
    // ...
}
```

And that's it.

---

If you want to see how to overload other operators and have a better understanding of this concept, I left for you some interesting resources.

**Introduction to operator overloading:**  
[https://www.learncpp.com/cpp-tutorial/introduction-to-operator-overloading/](https://www.learncpp.com/cpp-tutorial/introduction-to-operator-overloading/)

**TheCherno:**  
[https://www.youtube.com/watch?v=mS9755gF66w](https://www.youtube.com/watch?v=mS9755gF66w)

**CodeBeauty:**  
[https://youtu.be/BnMnozsSPmw?si=ZORSRExLocjHNJPi](https://youtu.be/BnMnozsSPmw?si=ZORSRExLocjHNJPi)

**C++ Logical (&&, ||, !) Operator Overloading:**  
[https://www.geeksforgeeks.org/cpp-logical-operator-overloading/](https://www.geeksforgeeks.org/cpp-logical-operator-overloading/)