This is a very basic operator overload question.
Say I had a class like this...
class xy
{
public:
double x, y;
XY(double X, double Y) { x = X; y = Y;}
XY operator+(const XY & add) const {
return XY(this->x + add.x, this->y + add.y);
}
XY & operator+=(const XY & add) const {?}
}
}
And I want operator+= do to what its supposed to do (you know, add to the current value of x and y). Wouldn't the code be the same for operator+ and operator +=?
How could it be the same? They do different things.
If you don't care about optimizations you can use += in your + operator implementation:
XY operator + (const XY& right) const
{
XY left(*this);
left += right;
return left;
}
Yep, do the add operation (stick to the += operator), and return a reference to itself. Oh, and this can't be a const method.
XY & operator+=(const XY & add) {
this->x += add.x;
this->y += add.y;
return *this;
}
No. Conventionally, operator+ stores the result in a new object and returns it by value, whereas operator+= adds the right-hand side to *this and returns *this by reference.
The two operators are related -- and can often be implemented in terms of one another -- but they have different semantics and therefore can't have identical implementations.
Related
In c++, why we must overloading +=, -=, +, - operator beside just overloading + and - operator? Here is an example:
In C++, when I create a Point class, I will do:
class Point {
public:
int x, y;
public:
Point(int X, int Y) : x(X), y(Y) {}
//Assignment operator
void operator=(Point a) { x = a.x; y = a.y; }
//The += and -= operator, this seem problematic for me.
void operator+=(Point a) { x += a.x; y += a.y; }
void operator-=(Point a) { x -= a.x; y -= a.y; }
//The + and - operator
Point operator+(Point a) { return Point(x + a.x, y + a.y); }
Point operator-(Point a) { return Point(x - a.x, y - a.y); }
};
But in some other language like C# for example, we don't need to overloading the += and -= operator:
public class Point {
public int x, y;
public Point(int X, int Y) {
x = X; y = Y;
}
//We don't need to overloading =, += and -= operator in C#, all I need to do is overload + and - operator
public static Point operator+(Point a, Point b) { return Point(a.x + b.x, a.y + b.y); }
public static Point operator-(Point a, Point b) { return Point(a.x - b.x, a.y - b.y); }
}
And both will work same as c++!
So I already know that if we overloading like c++, we can easier control which operator this class can have. But what else it can do?
I'm also new in c++ and I just learn overloading operator today.
The typical operator+= is more efficient than a = a + b, and cannot be implemented in terms of operator+. It can be the other way around though:
struct foo {
int value = 42;
foo& operator+=(const foo& other) {
this.value += other.value;
return *this;
}
foo operator+(const foo& other) const {
foo result = *this;
result += other; // reuse operator+=
return result;
}
};
Note how operator+ must create a new instance, while operator+= merely adds member of already existing instances.
In general operator+= can do something else entirely and might not be related to operator+ at all.
The same holds for operator-= vs operator-.
The questions that should be asked are rather:
Why C# wont allow overloading assignment operator?
Why C++ can't automatically do += if you have overloaded '+' and '=' operators?
The first question is discussed here with an excellent answer: https://stackoverflow.com/a/599582/6035486
TDLR; Due to garbage collection and reference counting, the compiler must be sure that the left side operand of an assignment statement (which is a reference because in C# class instances are references) is invalidated during the assignment hence its reference count must decrease by one. If user-defined assignment logic is allowed and anything can happen in an assignment operator, this mechanism of garbage collection would not work. Sorry this was supposed to be TLDR.
The answer to the second question is the same reason why defining operator== won't automatically give you operator!= and it should also be defined separately.
This question already has answers here:
Error using custom operator< with std::less
(2 answers)
Closed 6 years ago.
I was attempting to create a simple vector class when I encountered a problem.
This is a snippet of my code:
class Vector2D{
protected:
int x, y;
public:
Vector2D operator - (const Vector2D&);
friend int SumDiff(const Vector2D& obj1, const Vector2D& obj2);
};
Vector2D Vector2D::operator - (const Vector2D& param)
{
Vector2D obj;
obj.x = x - param.x;
obj.y = y - param.y;
return obj;
}
int SumDiff(const Vector2D& obj1, const Vector2D& obj2)
{
int result;
Vector2D obj3;
obj3 = obj1 - obj2;
result = obj3.x + obj3.y;
return result;
}
The line obj3 = obj1 - obj2; is highlighted as an error. Specifically, the operator- in this line does not seem to take Vector2D objects as operands.
The same problem occurs even if the SumDifffunction is part of the Vector2D class.
This code only seems to compile if the operator- is overloaded as a non-member function. Why?
Thanks in advance.
Your operator must be declared as const:
Vector2D operator - (const Vector2D&) const;
Else, you cannot use it with obj2, which is const.
As commented by NathanOlivier, you can also declare this operator outside the class as:
Vector2D operator - (const Vector2D& left, const Vector2D& right)
{
Vector2D obj;
obj.x = left.x - right.x;
obj.y = left.y - right.y;
return obj;
}
Then, you need to make it be a friend of your class (or add setters/getters), so that x and y can be accessed.
Your operator - member function is not marked as const, which means it:
states that it can modify the state of *this (the left-hand opearnd)
therefore cannot be called with a const-qualified object as the left-hand operand
Since operator - should most certainly not modify either of its operands, simply mark it const:
Vector2D operator - (const Vector2D&) const;
Note that in general, it's usually better to implement binary operators as non-members where possible. The reason is symmetry in implicit conversions. A binary operator implemented as a member can use implicit conversions on its right-hand side operand, but cannot use them on the left-hand side one (since the operand would need the proper type to find the operator in the first place).
Since you normally also want the compound assignment operators to exist, a common pattern is to implement the non-member binary operators in terms of the compound assignment, like this:
Vector2D& Vector2D::operator -= (const Vector2D &rhs)
{
x -= rhs.x;
y -= rhs.y;
return *this;
}
Vector2D operator - (Vector2D lhs, const Vector2D &rhs)
{
lhs -= rhs;
return lhs;
}
Finally, for use in production, consider using Boost.Operators to do most of this automatic delegation for you.
I'm writing a game in C++ for my Arduino and I've recently found the joys of operator overloading in structs. So far so good! I'm now stuck on the syntax to overload operators on properties. I want to implement something like this so that if my x or y values increase over the screen width I wrap the value back to 0. Many thanks!
// My guess :(
x& operator++(x &newx, int){
if (x == SCREEN_WIDTH - 1)
return 0;
else
return x + 1;
}
My struct definition is:
struct point_t
{
uint8_t x;
uint8_t y;
x& operator++(x &newx, int){
if (x == SCREEN_WIDTH - 1)
return 0;
else
return x + 1;
}
point_t& operator=(const point_t &p)
{
x = p.x;
y = p.y;
return *this;
}
bool operator==(const point_t &p) const
{
return (x == p.x && y == p.y);
}
bool operator!=(const point_t &p) const
{
return !(x == p.x && y == p.y);
}
};
You can't do this exactly as written. The return type of operator should be type.
What you can do is to create a new type, say coordinate, overload operator++ for it, and have your x (and y) have coordinate type, not uint8_t.
Possible solution (based on code by #MrMase):
template<uint8_t MAX>
class coordinate_t
{
private:
int8_t _p;
public:
coordinate_t(int8_t p = 0): _p(p) {}
// Postfix ++
coordinate_t operator++(int)
{
coordinate_t p(_p);
++_p;
if (_p > MAX - 1)
_p = 0;
return p;
}
// Postfix --
coordinate_t operator--(int)
{
coordinate_t p(_p);
--_p;
if (_p < 0)
_p = MAX - 1;
return p;
}
int get() const {return _p;}
};
typedef coordinate_t<SCREEN_WIDTH> xcoordinate_t;
typedef coordinate_t<SCREEN_HEIGHT> ycoordinate_t;
I've made it a template to allow for a simple typedef to define different coordinates; you might also have made MAX a private field and subclass it for different coordinates. In fact, it seems that the template solution is more safe, as it will not allow you to mix different coordinates; however, you might want to reconsider this based on your actual usage.
See full example: http://coliru.stacked-crooked.com/a/5a34261310d05a54
When overloading unary operators (operators with only a single operand, like the increase/decrease operators ++ and --) as member functions, they don't have an argument since they are performed on this. The exceptions being the dummy int arguments for the postfix increase/decrease operators.
The returned value differs depending on which operator you overload, but generally for unary operator you return a reference to object, i.e. *this.
Example
struct point_t
{
int x;
// Prefix increase operator
point_t& operator++()
{
++x;
return *this;
}
// Postfix increase operator
point_t operator++(int)
{
point_t old(*this); // Create new object using copy-constructor
operator++(); // Call prefix operator++ on `this`
return old; // Return old value, before increment
}
...
};
It's all documented in this operator overloading reference, as well as plenty of tutorials all over the Internet.
On an unrelated note, that operator!= can be implemented by using the == operator that you have already implemented:
bool operator!=(const point_t& p) const
{
return !(*this == p);
}
It's always a good idea to use existing operators when creating related operator overloads.
It seems it's not possible to overload a property of an enum so I'm going to do the next best thing: create a new type called xcordinate and overload the ++operator
Thanks very much to everyone who helped. I'm grateful! :)
I have multiple errors that say either "<snippet of code> needs zero or one argument" or "<snippet of code> needs exactly one argument." For the sake of simplicity I will only post one of these sections of code from my file.h and my file.cc. I don't believe there is anything wrong with my main.cc. Also, the function must be a friend function of the class my_int, so I cannot make it a different type of function or simply use accessor functions. Any help anyone could provide would be most appreciated. Thank you!
file.cc
(friend function of my_int class):
my_int my_int::operator+(const my_int& num1, const my_int& num2) {
my_int temp;
temp = num1 + num2;
return(temp);
}
file.h
(inside a class named my_int)
friend my_int operator+(const my_int& num1, const my_int& num2);
friend my_int operator+(const my_int& num1, const my_int& num2);
means 'declare a free function which takes 2 parameters. Make it a friend so it can see my private members'
my_int my_int::operator+(const my_int& num1, const my_int& num2) {
means 'define the (illegal) member function operator+ which takes total 3 arguments.
EDIT: by request, adding some more info.
There are a number of "correct" ways to implement operators on your classes. The 'best practice' way is to implement all binary operators as free functions (operator+ as a free function is declared with 2 parameters). Operator+ should be implemented where possible in terms of operator+= (a unary operator, therefore define it in the class). It's best practice because it allows you to write overloads of operator+ that take different objects as arguments. For example:
struct X {
explicit X(int val) : _val (val) {}
// getter
int value() const { return _val; }
// this helper += operator eases our journey later on
X& operator+=(int delta) {
_val += delta;
return *this;
}
X& operator+=(const X& r) {
_value += r.value();
return *this;
}
private:
int _val;
}
// implements X + X
X operator+(X l, const X& r)
{
return l += r;
}
// implements X + int
X operator+(X l, int r)
{
return l += r;
}
// implement int + X (returns an X)
X operator+(int l, X r) {
return r += l;
return r;
}
// later, someone else defines a Y and wants it to be addable with X, returning a Z
struct Y {
vector<int> get_numbers() const;
}
struct Z {
Z(vector<int> v);
}
// implement Z = X + Y;
Z operator+(const X& l, const Y& r) {
auto v = r.get_numbers(); // vector<int> instead of auto for c++03
v.push_back(l.value());
return Z { std::move(v) }; // c++11
// return Z(v); // c++03
}
// also implement Z = Y + X
Z operator+(const Y&l , const X&r) {
auto v = l.get_numbers();
v.push_back(r.value());
return Z { std::move(v) };
}
Note that it's possible to declare the free-function forms of binary operators as friends:
struct X {
// this is a free function - not a class memeber, but it can see X::_value
friend X operator+(X, const X&);
private:
int _value;
};
// implementation
X operator+(X l, const X& r) {
l._value += r._value;
return l;
}
but I would argue that this style is less preferable to writing truly unbound free binary operators that are implemented in terms of unary operators (above).
It's also possible to implement binary operators as member functions - in which case they are declared and defined with one parameter (the other being implied as this):
struct X {
X operator+(X r);
private:
int _value;
};
X X::operator+(const X& r) {
// l is implied as *this
return X { _value + r._value };
}
but this is a mistake because while it allows the overload of (X + int), it does not allow overloading (int + X), for which you'd need a free function anyway.
This method:
my_int my_int::operator+(const my_int& num1, const my_int& num2);
is a member function. A member function operator implicitly takes as its left parameter the object pointed to by this (which will be a my_int object). That means that your overload's parameter declaration can't contain more than one object. Change your signature to:
my_int my_int::operator+(const my_int& num2);
Now what was num1 previously is now *this.
The operator + can be used in two kinds of expressions:
unary "plus" expression: +a
binary "plus" expression: a + b
The operator is overloadable for both kinds of expressions. Each overload must be either unary or binary. If the overload is a member function, then the implicit instance argument provides the first operand.
So you have these options:
Free functions:
R operator+(T a) is eligible for +a when a is convertible to T.
S operator+(T lhs, U rhs); is eligble for a + b when a is convertible to T and b to U.
Member functions:
struct Foo
{
R operator+(); // #1
S operator+(T rhs); // #2
} x;
Overload #1 is eligible for +x.
Overload #2 is eligible for x + b when b is convertible to U.
When a class overloads operator+, should it be declared const since it does not do any assignment on the object?
Also, I know that operator= and operator+= return a reference because an assignment is made. But, what about operator+? When I implement it should I make a copy of the current object, add the given object to that, and return that value?
Here is what I have:
class Point
{
public:
int x, int y;
Point& operator += (const Point& other) {
X += other.x;
Y += other.y;
return *this;
}
// The above seems pretty straightforward to me, but what about this?:
Point operator + (const Point& other) const { // Should this be const?
Point copy;
copy.x = x + other.x;
copy.y = y + other.y;
return copy;
}
};
Is this a correct implementation of the operator+? Or is there something I am overlooking that could cause trouble or unwanted/undefined behavior?
Better than that, you should make it a free function:
Point operator+( Point lhs, const Point& rhs ) { // lhs is a copy
lhs += rhs;
return lhs;
}
But yes, if you leave it as a member function it should be const as it does not modify the left hand side object.
Regarding whether to return a reference or a copy, the advice for operator overloading is do as fundamental types do (i.e. do as ints do). In this case, addition for two integers returns a separate integer that is not a reference to neither one of the inputs.