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;
}
Related
class myClass
{
public:
int myVal;
myClass(int val) : myVal(val)
{
}
myClass& operator+(myClass& obj)
{
myVal = myVal + obj.myVal;
return *this;
}
myClass& operator+(int inVal)
{
myVal = myVal + inVal;
return *this;
}
myClass& operator=(myClass& obj)
{
myVal = obj.myVal;
return *this;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
myClass obj1(10);
myClass obj2(10);
obj1 = obj1 + obj2;
obj1 = 20 + obj2; // Error : No matching operands for operator "+"
return 0;
}
How can I implement operator '+' on integer and myClass object types as operands? (obj1 = 20 + obj2)
You typically implement the binary arithmetic += (compound-assignment) operator as a member function, and + as a non-member function which makes use of the former; this allows providing multiple overloads of the latter e.g. as in your case when the two operands to the custom binary arithmetic operators are not of the same type:
class MyClass
{
public:
int myVal;
MyClass(int val) : myVal(val) {}
MyClass& operator+=(int rhs) {
myVal += rhs;
return *this;
}
};
inline MyClass operator+(MyClass lhs, int rhs) {
lhs += rhs;
return lhs;
}
inline MyClass operator+(int lhs, MyClass rhs) {
rhs += lhs;
return rhs;
// OR:
// return rhs + lhs;
}
int main() {
MyClass obj1(10);
MyClass obj2(10);
obj1 = 20 + obj2;
obj1 = obj1 + 42;
}
For general best-practice advice on operator overloading, refer to the following Q&A:
What are the basic rules and idioms for operator overloading?
Let us say My class contain object t1. I have to add 5 along with t1.
cout<<5+t1
Please post an example which satisfies the above conditions.
Assuming you have a type MyClass you can provide an operator+ for it and int like so:
MyClass operator+(MyClass lhs, int rhs) {
return /* ... */ ;
}
Though you want to make it commutative so add one with the reverse order as well
MyClass operator+(int lhs, MyClass rhs) {
return rhs + lhs;
}
As a complete example:
#include <iostream>
struct MyClass {
int value = 0;
};
MyClass operator+(MyClass lhs, int rhs) {
lhs.value += rhs;
return lhs;
}
MyClass operator+(int lhs, MyClass rhs) {
return rhs + lhs;
}
int main() {
MyClass mc{3};
auto result = mc + 5;
std::cout << result.value << '\n';
}
And at this point it's usually benefical to have a += as well. It's easy to implement + in terms of +=
MyClass& operator+=(MyClass& lhs, int rhs) {
lhs.value += rhs;
return lhs;
}
MyClass operator+(MyClass lhs, int rhs) {
lhs += rhs;
return lhs;
}
MyClass operator+(int lhs, MyClass rhs) {
return rhs + lhs;
}
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.
If I have a simple class like this:
template<typename T>
class coord
{
public:
coord() : x(0), y(0)
{
}
coord(T X, T Y) : x(X), y(Y)
{
}
T x;
T y;
coord& operator-=(const coord& rhs)
{
(*this).x -= rhs.x;
(*this).y -= rhs.y;
return *this;
}
coord& operator+=(const coord& rhs)
{
(*this).x += rhs.x;
(*this).y += rhs.y;
return *this;
}
};
Along with the following operators (they're not friends because there's no private members to access).
template<typename T = int>
inline coord<T> operator-(coord<T> lhs, const coord<T>& rhs)
{
lhs -= rhs;
return lhs;
}
template<typename T = int>
inline coord<T> operator+(coord<T> lhs, const coord<T>& rhs)
{
lhs += rhs;
return lhs;
}
Elsewhere in my code I have another class A with a method that looks like this:
void A::SetVarC(coord<int>& c)
{
m_c = c;
}
(assume there's a getter for m_c as well)
When I try to invoke this method using the addition and subtraction operators I overloaded:
int x = 1;
int y = 1;
A* a = new A();
coord c1(1,2);
a->SetVarC(c1 - a->GetVarC() + coord<int>(x,y));
I get an error that there's no known conversion from coord<int> to coord<int>&. I can see that my subtraction and addition operators aren't returning references, but I thought that wouldn't matter. I am using C++11... are move semantics coming into play here?
Temporary cannot be bind to non const reference, change SetVarC to
void A::SetVarC(const coord<int>& c)
{
m_c = c;
}
or
void A::SetVarC(coord<int> c)
{
m_c = std::move(c);
}
You are passing a temporary coord<int> object to A::SetVarC() which requires a non-const reference, which is not possible.
You should fix your code by changing A::SetVarC() to accept a const coord<int>&.
You're creating arithmetic operators with a side affect...
These operators shouldn't change the value of the arguments used.
And, to the answer your question, these methods return a temporary object, that can't be passed as reference to SetVarC.
template<typename T = int>
inline coord<T> operator-(const coord<T>& lhs, const coord<T>& rhs)
{
coord<T> res(lhs)
res -= rhs;
return res;
}
template<typename T = int>
inline coord<T> operator+(const coord<T>& lhs, const coord<T>& rhs)
{
coord<T> res(lhs)
res += rhs;
return res;
}
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;
}