In the previous lesson, we created a simple Vector3
struct to hold 3 numbers, represending a 3D position:
struct Vector3 {
float x;
float y;
float z;
}
It would be nice if we were able to use operators like +
and +=
with our new custom type, in much the same way we were able to do with types like int
and float
.
For example, we would like to be able to do things like this:
Vector3 CurrentPosition { 1.0, 2.0, 3.0 };
Vector3 Movement { 4.0, 5.0, 6.0 };
// Create a new object using the + operator
Vector3 NewPosition { CurrentPosition + Movement };
After running the above code, we'd want NewPosition
to be a Vector3
with the values 5.0
, 7.0
and 9.0
.
We'd also like to be able to do the following, to update the CurrentPosition
vector directly:
Vector3 CurrentPosition { 1.0, 2.0, 3.0 };
Vector3 Movement { 4.0, 5.0, 6.0 };
// Update an existing object using the += operator
CurrentPosition += Movement;
For this, we need to overload operators.
In C++, operators are simply functions that have a specific name and parameter list.
When we write code like 1 + 2
, the compiler is going to try to call a function with the following properties:
operator+
int
as the first argumentint
as the second argumentWith that in mind, lets create a function to be the +
operator that can be used with two Vector3
objects:
void operator+ (Vector3 a, Vector3 b) {
}
With those additions, we can now write the following code, and have our program compile successfully:
CurrentPosition + Movement;
Of course, we want that expression to actually return a useful value. So, lets implement our function, by updating its return type, and adding an appropriate return statement:
Vector3 operator+ (Vector3 a, Vector3 b) {
return Vector3 { a.x + b.x, a.y + b.y, a.z + b.z };
}
With that, we can now easily add our Vector3
objects together!
There are some improvements we can make. Our function is currently accepting the structs by value. We can change this to be pass by reference instead, as we have no need to create a copy of our incoming objects.
Further, since our operator is not modifying the input objects, we can make those references const
.
Vector3 operator+ (const Vector3& a, const Vector3& b) {
return Vector3 { a.x + b.x, a.y + b.y, a.z + b.z };
}
What function signature would we need to make line 4 work?
1Vector3 CurrentPosition { 1.0, 2.0, 3.0 };
2Vector3 Reverse { 4.0, 5.0, 6.0 };
3
4Vector3 NewPosition { CurrentPosition - Reverse };
5
What function would we need to allow a vector to be multiplied by an integer?
1Vector3 CurrentPosition { 1.0, 2.0, 3.0 };
2
3Vector3 NewPosition { CurrentPosition * 5 };
4
The previous examples implemented operator overloading using a standalone function. However, it is also possible to implement it by having our function be a member of our struct or class.
Lets see what the +
operator might look like using that method:
struct Vector3 {
float x;
float y;
float z;
Vector3 operator+ (const Vector3& Other) {
return Vector3 {
x + Other.x,
y + Other.y,
z + Other.z
};
}
};
Vector3 MyVector { 1.0, 2.0, 3.0 };
Vector3 OtherVector { 1.0, 2.0, 3.0 };
Vector3 CombinedVector { MyVector + OtherVector };
The key thing to note in the declaration of operator+
within the struct is that there is only one parameter.
This might be confusing, as the +
operator has two operands - a left and a right. Indeed, when we created this as a standalone function earlier, we needed to have two parameters:
Vector3 operator+ (const Vector3& a, const Vector3& b) {
return Vector3 { a.x + b.x, a.y + b.y, a.z + b.z };
}
However, when when we overload the operator as a member function, the function is called within the context of the left operand. Therefore, there is no need to have the left operand be provided as an argument - we can just access its class members in the same way we would any other class function.
How can we allow our Vector3
objects to be multiplied with a float
using a member function operator overload?
struct Vector3 {
float x;
float y;
float z;
// Add a function here
};
Vector3 MyVector { 4.0, 5.0, 6.0 };
Vector3 BigVector { MyVector * 3 };
Like any other class or struct function, we can declare and define them in different locations, if we want. This would be useful if we want to have a seperate .h
and .cpp
file:
// Header File
struct Vector3 {
float x;
float y;
float z;
Vector3 operator+ (const Vector3& Other);
};
// CPP File
Vector3 Vector3::operator+ (const Vector3& Other) {
return Vector3 {
x + Other.x,
y + Other.y,
z + Other.z
};
}
This lesson focused on overloading binary operators. Binary operators are those that take two operands - a left and a right.
We've also seen unary operators in the past, like ++
, *=
and !
. These operators only operate on one object.
We'll see how we can overload those in the next lesson!
Become a software engineer with C++. Starting from the basics, we guide you step by step along the way