tags:
- Cpp
Operator Overloading in C++ (ENG)
We introduce operator overloading mainly to address situations where the existing operators do not align with the unique properties of a class. Besides the concept, you will also learn some in-depth details about how it works. Here is what you will learn in this note:
C++ provides us a lot of operators, and some special operators like new
and new[]
, delete
and delete[]
, as well as co_await
since C++20. Before we go under the hood, let's first take a look at the kinds of operators we have in C++.
Binary operators operate on two operands. Here are the binary operators in your list:
+
, -
, *
, /
, %
(Arithmetic operators)^
, &
, |
(Bitwise operators)=
, +=
, -=
, *=
, /=
, %=
, ^=
, &=
, |=
, <<=
, >>=
(Assignment operators)<
, >
, <=
, >=
, ==
, !=
, <=>
(Comparison operators)&&
, ||
(Logical operators)<<
, >>
(Bitwise shift operators),
(Comma operator)->*
, ->
(Member access operators)[]
, ()
(Subscript and function call operators)Unary operators operate on a single operand. Here are the unary operators in your list:
~
(Bitwise NOT)!
(Logical NOT)++
, --
(Increment and Decrement operators)Such as new
, new[]
etc...
Later, we will create an overloaded operator ourselves. Before that, it's important to understand that different operators play a significant role in operator overloading. We categorized these operators into binary and unary operators, their signatures can vary depending on the operator.
Those signatures match the following:
Expression | As member function | As non-member function | Example |
---|---|---|---|
@a | (a).operator@ ( ) | operator@ (a) | ++obj; |
a@b | (a).operator@ (b) | operator@ (a, b) | obj3 = obj1 + obj2; |
a@ | (a).operator@ (0) | operator@ (a, 0) | obj++; |
And be aware, the operators =
, ()
, []
, and ->
cannot be non-member functions for specific reasons, Copilot says this is because those operators need direct access to the object.
We use the keyword operator
to define operator overloading, which allows us to provide custom implementations for operators in user-defined types or classes. When you overload an operator, it behaves exactly like a function with a special name, different parameter means different function symbol. And yes, this is a familiar concept we known as static polymorphism.
+
#include <iostream>
#include <cstring>
struct vector {
float x, y, z;
vector operator+(const vector& rhs) const {
vector result;
result.x = this->x + rhs.x;
result.y = this->y + rhs.y;
result.z = this->z + rhs.z;
return result;
}
};
struct string{
char* str;
int str_len;
string(const char* s = "") {
str_len = std::strlen(s);
str = new char[str_len + 1];
for(int i = 0; i < str_len + 1; i++)
str[i] = s[i];
}
~string() {
delete[] str;
}
string operator+(const string& other) const {
int new_length = str_len + other.str_len;
char* new_str = new char[new_length];
std::strcpy(new_str, str);
std::strcat(new_str, other.str);
return string(new_str);
}
};
int main() {
vector v1 = {1.0, 2.0, 3.0};
vector v2 = {4.0, 5.0, 6.0};
vector v3 = v1 + v2;
std::cout << "Result: (" << v3.x << ", " << v3.y << ", " << v3.z << ")" << std::endl;
string s1 = string("hello, ");
string s2 = string("world!");
string s3 = s1 + s2;
std::cout << "Result: " << s3.str << std::endl;
return 0;
}
++
<<
new
and delete
inline
Overloading for Comparison OperatorsFor operators that are simple to implement, we usually use the inline
keyword to instruct the compiler to inline the overloaded operator. We can get several benefits after this: