What is the preferred way to override operators in C++ - c++

I was always overriding operators like this:
class MyClass {
public:
...
MyClass operator+(const MyClass&) const;
private:
int some_number = 5;
}
 
MyClass MyClass::operator+(const MyClass& rhs) const
{
return MyClass(some_number + rhs.some_number);
}
But today I realized you can create operators with the 'friend' keyword too:
class MyClass {
public:
...
friend MyClass operator+(const MyClass&, const MyClass&);
private:
int some_number = 5;
}
 
MyClass operator+(const MyClass& lhs, const Myclass& rhs)
{
return MyClass(lhs.some_number + rhs.some_number);
}
Which would be the preferred way considering I want left-sided and right-sided operators and I also (try to) follow the Core Guidelines?

The preferred way is to not even make it a friend:
MyClass operator+(MyClass lhs, Myclass const& rhs)
{
return lhs += rhs;
}
Of course, this does rely on operator+= but that is the more fundamental operation. += alters its left-hand side and should be a member.

Related

What is the proper way of returning a new instance of an immutable?

I would like to leave the two instances unchanged, and return a new one.
Currently I am doing it this way:
class myClass {
public:
myClass operator +(const myClass &obj) {
myClass ret = *this;
// some operation
return ret;
}
// functions...
};
It works, but I am not sure, if it is the correct way
Edit
The operator + is just an example. I'm just curious, how the immutable functions/methods should be written in C++
If myClass is supposed to be immutable under addition, you probably want to make operator+ a free function rather than a class member. (You might have to make it a friend function.)
myClass operator+(const myClass &lhs, const myClass &rhs) {
return myClass( /* some operation */ );
}
Note that both operands are taken by const reference, so you know you cannot accidentally change them (maintaining the immutability property). You're returning a new instance of myClass, which is now immutable. You construct and return the result in one step, because, if myClass really is immutable, you might not be able to default construct one and then set its value.
Here's a stupid example:
class myClass {
public:
explicit myClass(int x) : m_x(x) {}
friend myClass operator+(const myClass &lhs, const myClass &rhs);
private:
int m_x;
};
myClass operator+(const myClass &lhs, const myClass &rhs) {
return myClass(lhs.m_x + rhs.m_x);
}
If you really want to implement it as a class method, the method should be marked const to ensure the implementation doesn't accidentally mutate the left-hand instance.
Binary arithmetic operators (like operator+) are often defined in terms of the arithmetic self-assignment operators (like operator+=), which are obviously not immutable. If we add this method to myClass:
myClass &operator+=(const myClass &rhs) {
m_x += rhs.m_x;
return *this;
}
Then the common idiom for defining operator+ would be:
myClass operator+(const myClass &lhs, const myClass &rhs) {
myClass result = lhs;
result += rhs;
return result;
}
Now the implementation of operator+ doesn't require any of the private members of the class, so it no longer needs to be declared as a friend function.

Operator overloading of private inner members

Is it possible to overload a private inner class member as a non-member? It seems to me the only way is to overload as a member.
class Foo
{
private:
struct Bar
{
int a;
char b;
Bar& operator+=(const Bar& rhs)
{
a += rhs.a;
return *this;
}
// Only possibility?
inline Bar operator+(const Bar& rhs)
{
Bar bar;
bar.a = this->a + rhs.a;
bar.b = this->b;
return bar;
}
};
// Cannot do this as takes implicit reference (to Foo?).
inline Bar operator+(Bar lhs, const Bar& rhs)
{
lhs += rhs;
return lhs;
}
};
// Cannot do this as Bar private.
inline Foo::Bar operator+(Foo::Bar lhs, const Foo::Bar& rhs)
{
lhs += rhs;
return lhs;
}
I guess I could just use the member overload, but I understand it's preferable to overload the + operator as a non-member, and I would like to separate the implementation.
Doesn't look like anyone wants to claim this, I'll provide the answer for completeness. Credit goes to juanchopanza and Igor Tandetnik.
The solution is to use friend.
class Foo
{
private:
struct Bar
{
int a;
char b;
Bar& operator+=(const Bar& rhs)
{
a += rhs.a;
return *this;
}
};
friend Bar operator+(Bar, const Bar&);
};
Foo::Bar operator+(Foo::Bar lhs, const Foo::Bar& rhs)
{
lhs += rhs;
return lhs;
}

Overloading operator= for structs, within classes

We have the following:
(pseudoish)
class MyClass
{
private:
struct MyStruct{
MyStruct operator=(const MyOtherStruct& rhs);
int am1;
int am2;
};
};
We'd like to overload the = operator in the MyClass.cpp to do something like:
MyStruct&
MyStruct::operator=(const MyOtherStruct& rhs)
{
am1 = rhs.am1;
am2 = rhs.am2;
}
However, it doesn't want to compile. We're getting an error similar to
"missing ; before &"
and
"MyStruct must be a class or namespace if followed by ::"
Is there some concept here I'm missing?
You need to move your operator= for MyStruct into the struct declaration body:
class MyClass
{
private:
struct MyStruct{
int am1;
int am2;
MyStruct& operator=(const MyOtherStruct& rhs)
{
am1 = rhs.am1;
am2 = rhs.am2;
return *this;
}
};
};
Or if that's not possible because MyOtherStruct is incomplete or don't want to clutter the class declaration:
class MyClass
{
private:
struct MyStruct{
int am1;
int am2;
MyStruct& operator=(const MyOtherStruct& rhs);
};
};
inline MyClass::MyStruct& MyClass::MyStruct::operator=(const MyOtherStruct& rhs)
{
am1 = rhs.am1;
am2 = rhs.am2;
return *this;
}
The syntax is
MyStruct& operator=(const MyOtherStruct& rhs) {
// assignment logic goes here
return *this;
}
for an operator directly within the body of MyStruct. Also note that I added the idiomatic return *this to let the assignment return a reference to this object.
EDIT in response to OP editing the question.
You can also declare the operator in the body, and define it somewhere else. In this case, the syntax is:
MyClass::MyStruct& MyClass::MyStruct::operator=(const MyOtherStruct& rhs) {
// assignment logic goes here
return *this;
}

Why does a function have the word constant at the end even though it does change a variable

My understanding of the keyword 'const' is that it says to the compiler, that the function will not modify any of the variables but in the following example it changes b.d. why?
myClass operator + (myClass b) const { b.d += d; return b; }
const function can't modify variables of this(the calling object) (if variable is not mutable). in example this is not modified. so, it's correct.
variable b is another object of class myClass.
myClass operator + (myClass b) const
is
myClass operator + (const myClass* this, myClass b)
better to use member-operator += and not member operator +, for example
myClass& myClass::operator += (const myClass& rhs)
{
d += rhs.d;
return *this;
}
myClass operator + (const MyClass& lhs, const MyClass& rhs)
{
myClass tmp(lhs);
tmp += rhs;
return tmp;
}

Preventing code duplication for functions with signatures differing only by lvalue/rvalue semantics

I need to implement functions (operators to be specific) with signatures looking like this:
friend MyClass operator+(MyClass&& lhs, MyClass& rhs);
friend MyClass operator+(MyClass&& lhs, MyClass&& rhs);
friend MyClass operator-(MyClass&& lhs, MyClass& rhs);
friend MyClass operator-(MyClass&& lhs, MyClass&& rhs);
MyClass& operator+=(MyClass& other);
MyClass& operator+=(MyClass&& other);
MyClass& operator-=(MyClass& other);
MyClass& operator-=(MyClass&& other);
These are 8 functions, but morally there are only two implementations, as all + and - operations are basically the same. I'd like to avoid writing the same thing 4 times only to cater to different rvalue signatures. Is there a canonical way to do this? I came up with something like this:
MyClass& operator+=(MyClass&& other) {
... // Actual implentation details.
return *this;
}
MyClass& operator+=(MyClass& other) {
return *this += std::move(other);
}
MyClass operator+(MyClass&& lhs, MyClass&& rhs) {
auto myClass = MyClass(); // Copy ctor is deleted.
myClass += rhs;
return myClass;
}
MyClass operator+(MyClass&& lhs, MyClass& rhs) {
return std::move(lhs) + std::move(rhs);
}
// Similar implementations for operator- and operator-=.
This seems to work, but since I'm not really confident in the world of move semantics I'm unsure whether I wrote something horrible and there's a much easier and cleaner way to do this. For example, what is the overhead of using std::move? Are there side-effects I'm unaware of?