You know that there is a list of overrideable operators in C++:
http://msdn.microsoft.com/en-us/library/5tk49fh2%28v=vs.80%29.aspx[
^]. If you take a look at the list you quickly realize that almost every of these operators are used by some of the built in primitive C++ types: bool, int, float, pointer. You can write operators for any classes you use but its very easy to overuse and abuse operator overloading. You should use it only when the class you have written is something that works similarly to one of the previously mentioned primitive types:
- For exampe a 3D application can define operators for its vector and matrix classes because those use the same mathematical operators as numbers (int/float). Another good example to this is a string class where the + opeator is nice for string concatenation.
- A smart pointer might want to redefine the -> operator to mimic the primitive 'raw' pointers (also the prefix* and pre/postfix ++ and -- operators). It also wants to define some conversion operators to the raw pointer type in encapsulates. The same is true for C++ iterators that mimic pointers and add debug functionality.
- In almost every classes you want to define the assignment (=) operator to define or disable copying.
Code example:
struct vec2
{
float x, y;
vec2(float _x, float _y)
: x(_x), y(_y)
{}
vec2& Add(const vec2& other)
{
x += other.x;
y += other.x;
return *this;
}
vec2& operator+=(const vec2& other)
{
x += other.x;
y += other.x;
return *this;
}
vec2 GetSumWith(const vec2& other)
{
return vec2(x+other.x, y+other.y);
}
vec2 operator+(const vec2& other)
{
return vec2(x+other.x, y+other.y);
}
vec2& MultiplyWith(float f)
{
x *= f;
y *= f;
return *this;
}
vec2& operator*=(float f)
{
x *= f;
y *= f;
return *this;
}
vec2 GetRightMultiplied(float f)
{
return vec2(x*f, y*f);
}
vec2 operator*(float f)
{
return vec2(x*f, y*f);
}
};
inline vec2 operator*(float f, const vec2& v)
{
return vec2(f*v.x, f*v.y);
}
int main(int argc, char* argv[])
{
vec2 a(0, 0);
vec2 b(1, 1);
a.Add(b);
a.operator+=(b);
a += b;
vec2 c(a.GetSumWith(b));
vec2 d(a.operator+(b));
vec2 e(a + b);
vec2 m = vec2(1, 2) * 5.0f;
vec2 n = 5.0f * vec2(1, 2);
return 0;
}
If you take a look at the example and check out the
Add()
operator and its use in the main method you immediately realize that the
Add()
and
operator+=()
methods are the same, only their name is different, and you can use
operator+=()
in two ways: by directly calling it or just by using
+=
. Some operators can be defined only inside the class (like assignment, conversion, unary operators), some can be defined both inside and outside the class (like +, -, /) and sometimes you can write an operator only as global: when the first operand of a binary operator is not your class: the example demonstrates this with the left-multiplay by a float. Note that your operators can return anything you want, but there are some conventions that C++ coders usually follow. For example my
operator+=
could return void, but its a convention that the value of a (something+=something) expression is the result of the addition and my code behaves like this. You could define for example write an operator that can add a dog and a cat type and then returns a cow type:
inline cow operator+(const cat& c, const dog& d)
{
}
cat c;
dog d;
cow(c + d);
The above example is a heavy abuse of operator overloading. If you have to do such thing then you should name the function for example like this:
CowFromCatAndDog()
. Some 3D math libraries also make abuse of operator overloading because there are usually 3 types of vector multiplications (dot, cross, per-component) while you have only one multiply (*) operator in C++. I think all of these operations should be used with named methods but they are often put these operations to C++ operators: * - dot, % - cross.
Summary: When you are overriding operators you basically define rules for your C++ compiler to call certian functions when they encounter the use of some operators with specific types. Note that you can not redefine the precedence of operators! You should almost never use operator overloading except when you are writing basic core libraries (like math vectors/smart pointers). The only operator that should be used often outside base libraries is the assignment operator. Operator overloading is often abused by beginners to shorten the function calls and not to mimic the behavior of basic types.