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.
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.
For instance if I have overloaded a + operator
myClass & operator + (const myClass & rhs)
and also overloaded = operator
myClass & operator = (const myClass & rhs)
both operators are working fine. Can I use this overloaded operator in my += operator overload?
myClass & operator += (const myClass & rhs){
*this = *this + progA;
return *this;
}
The above code is working okay. I just want to know if this is good code writing practice or I should re-use the code from the two previous implementations for the += operator overload.
You can do that. However, it is more common to implement operator+ using operator+= instead of the other way around.
myClass & operator += (const myClass & rhs) { ... )
// Return by value.
// const member function.
myClass operator + (const myClass & rhs) const
{
myClass ret = *this; // Uses copy constructor, not assignment.
return ret += rhs;
}
The interface
myClass & operator + (const myClass & rhs);
is not idiomatic since you cannot do the equivalent of
int a = 10 + 20;
Using
MyClass a = MyClass(args...) + MyClass(args...);
won't work since the first object in RHS is a temporary object.
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.
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.
We can overload assignment operator as a normal function, but we cannot overload assignment operator as a friend function. Why?
Because the C++ Standard says so, Article 13.5.3/1:
An assignment operator shall be
implemented by a non-static member
function with exactly one parameter.
Because a copy assignment operator
operator= is implicitly declared for a
class if not declared by the user
(12.8), a base class assignment
operator is always hidden by the copy
assignment operator of the derived
class.
That's all you really need to know. A friend function is not a member function, so it cannot be used to overload the assignment operator.
If you would like to write:
MyClassObject = MyFriendObject;
Then you would want to implement a constructor that takes a const reference to the friend class as it's parameter.
The difference between overloading by friend function and overloading by member function is that the calling object must be the first operand in overloading by member function, while there is no restriction in overloading by friend function. This is the reason behind the standard. Similarly, some other operators requiring the first operand to be the calling function must be overloaded using member functions (examples: =, [], ->, and ( )).
You cannot "extend" the assignment operator with a "free function" outside the class, but you can design the class so it will allow it:
Data.h
class Data {
public:
Data& operator=(const Data& lhs) { /*...*/; return *this; }
template <typename T> Data& operator=(const T& lhs) {
return assign(*this, lhs); // Magic right here...
}
private:
// ...
};
Point.h
class Point {
public:
float x,y;
Point& operator=(const Point& lhs) { x = lhs.x, y = lhs.y; return *this; }
template <typename T> Point& operator=(const T& lhs) {
return assign(*this, lhs); // Magic right here...
}
};
Assignment.h
Data& assign(const Data& lhs, const Point& rhs) {
lhs["x"] = rhs.x;
lhs["y"] = rhs.y;
return lhs;
}
Point& assign(const Point& lhs, const Data& rhs) {
rhs.query("x", lhs.x) || rhs.query(0, lhs.x);
rhs.query("y", lhs.y) || rhs.query(1, lhs.y);
return lhs;
}