I had a question on operator overloading. Below is my the example code. If you can read through it and my question is below.
//class definition
class example
{
private:
int a ; // Defined in FeetInches.cpp
public:
void seta(int f)
{
a = f;
}
example operator + (const example &); // Overloaded +
int geta()
{
return a;
}
};
example example::operator + (const example &right)
{
example temp;
temp.a = a + right.a;
return temp;
}
//main
#include "header" //this is the class definition above
#include <iostream>
using namespace std;
int main()
{
example r;
r.seta(1);
example s;
s.seta(1);
example t;
t = r + s;
t = r + 1; //if included it won't compile
t = 1 + r; //if included it won't compile
int x = t.geta();
cout << x;
cin.get();
return 0;
}
I understand that when you attempt to add to objects together using operator overloading they should be the same.
Here is the question:
I recently saw when the object was on one side of the operator it compiled but when it was on the other it didn't. Such as:
t = r + 1; it compiled.
t = 1 + r; it didn't.
(Also I know in my example it doesn't work either way but was just easier to frame question with code.)
How does operator overloading compile when the object is on one side of the operator but not compile when it is on the other.
Thanks
If you rewrite the offending statement verbosely, it looks like:
t.operator=(1.operator+(r));
Which doesn't make a lot of sense and confuses the compiler.
Being confused, it can either convert the number 1 to an instance of example or convert the variable r to an integer. Unfortunately, you don't supply enough information in your class to do either.
If you provide a constructor for your class that takes an integer, things may come out less confusing:
class example
{
public:
example(int new_value) : a(new_value)
{ ; }
};
Now you have provided the compiler with a method convert integers into examples.
Another alternative is to provide a casting or conversion operator:
class example
{
public:
int operator int (const example& e)
{
return e.a;
}
};
There are other alternatives, such as creating an addition method that takes an integer.
Edit 1:
If you are designing a units class beware of constants. You have no idea what unit the constant is in, such as feet or inches. The compiler won't be able to help, since numerical constants don't have units associated with them.
It's really simple, when you overloading operator you can do it in two ways:
First is like you do it. You inserted overloaded operator for your class in it. This way the left argument must be the object of this class. Why? Because when you call this operator you can do it as call of every function in your class. You can't do it other way, because you can't call this function by other type.
Second, you made overloaded operator as friend to your class.
In your class you put this line:
friend example& operator + (const example &left, const example &right);
And after your class definition you put this:
example& operator + (const example &left, const example &right){...}
So if you want to add integer or other types you must just modify your operator to add it like this:
example& operator + (const example &left, const int right){...}
or this:
example& operator + (const int left, const example &right){...}
Choose one or both if you want to add int from left or rigth side of the opearator.
t = r + 1; means t = r.operator+(1); if r defines a matching operator+() method, otherwise it means t = operator+(r, 1); instead. It does not compile because you did not define any + operator that takes an example on the left and an int on the right, eg:
// as a class method:
class example
{
...
public:
...
example operator + (int right) const;
};
example example::operator + (int right) const
{
example temp;
temp.seta(a + right);
return temp;
}
Or:
// as a global operator:
class example
{
...
public:
...
friend example operator + (const example& left, int right);
};
example operator + (const example& left, int right)
{
example temp;
temp.seta(left.a + right);
return temp;
}
If you had defined a contructor that takes an int as input, the compiler could have created a temp example when you pass an int value to the example::operator+(const example&) method, eg:
class example
{
...
public:
example (int f);
...
example operator + (const example& right);
};
example::example::(int f)
: a(f)
{
}
example example::operator + (const example& right)
{
example temp;
temp.a = a + right.a;
return temp;
}
Likewise, t = 1 + r; means t = operator+(1, r); (since 1 is not a class type). It does not compile because you did not define a global + operator that takes an int on the left and an example on the right:
class example
{
...
public:
...
friend example operator + (int left, const example& right);
};
example operator + (int left, const example& right)
{
example temp;
temp.a = left + right.a;
return temp;
}
Related
I want to use the - operator between 3 objects but I can't.
Error:'A A::operator-(A, A)' must take either zero or one argument
I do not know what to do.
class A
{
private:
float x,y;
public:
void set(int a,int b){
x=a;
y=b;
}
void show(){
cout<<"x = "<<x<<" y = "<<y<<endl;
}
A() {}
A operator -(A &obj1){
A temp;
temp.x= x - obj1.x;
temp.y= y - obj1.y;
return temp;
}
};
A A::operator -(A obj1, A obj2);
int main() {
A ob1,ob2,ob,result;
ob1.set(5,7);
ob2.set(10,7);
ob.set(4,9);
result = ob - ob2 -ob1;
ob.show();
return 0;
}
There are 2 ways to overload an operator for a class:
class Foo {
public:
Foo operator -(const Foo &rhs) const { ... }
Foo operator +(const Foo &rhs) const;
};
Foo Foo::operator +(const Foo &rhs) const {
...
}
or
class Foo { ... };
Foo operator -(const Foo &lhs, const Foo &rhs) { ... }
The first is overloading the operator inside the class as a function of the class. It has this as the left hand side of the operator so you can only specify the right hand side as argument.
The second overloads the general operator outside of the class. It has 2 arguments, the left hand side and the right hand side. It is not a member of the class and won't have access to the private parts, unless you friend it.
You kind of mixed the two styles together and that is what the error is trying to tell you.
You do not need to implement anything to make a - b - c work as the compiler will transform that into temp = a - b; temp - c;.
Let's say I have a class Number
class Number
{
public:
int numb;
Number (int g)
{
numb = g;
}
int operator+(int h)
{
return this->numb+h;
}
};
And when I try to use my overloaded operator
cout << 3 + s; // doesn't work
cout << s + 3;
I understand why it doesn't work, but I don't know how to make it work for 3 + s
Of course, I can write operator+ with 2 arguments outside the class, but I want to have my operator overloaded in the class.
I've googled it, but didn't find any solution.
Easiest way to go: write another overload outside of your class
class Number
{
public:
int numb;
Number (int g)
{
numb = g;
}
int operator+(int h)
{
return this->numb+h;
}
};
int operator+(int h, Number& n)
{
return n.numb+h;
}
int main()
{
int s = 42;
std::cout << 3 + s;
std::cout << s + 3;
}
Live Example
This also works if your data is private (but make sure the outside function has access to those members)
class Number
{
int numb;
public:
Number (int g)
{
numb = g;
}
int operator+(int h)
{
return this->numb+h;
}
friend int operator+(int, Number&);
};
int operator+(int h, Number& n)
{
return n.numb+h;
}
Of course, I can write operator+ with 2 arguments outside the class, but I want to have my operator overloaded in the class.
This is like saying "Of course I could hammer in my nail with a hammer, but I want to use a screwdriver..."
Some other solutions suggested using both a member and a non-member, but that is redundant: if you add the non-member then you no longer need the member!
The proper way to overload operator+ is to use the non-member:
Number operator+(Number a, Number b)
{
return a.numb + b.numb;
}
Another way to write this is to use operator+= as a helper (then your class will support += too):
Number operator+(Number a, Number b)
{
return a += b;
}
with member function:
Number &operator+=(Number b)
{
numb += b.numb;
return *this;
}
You could either make operator+ return Number or int, your choice.
Just write an operator outside the class that calls the one in your class!
template<typename T> T operator+(T a, Number& n)
{
return n+a;
}
I have a problem in inheriting overloaded + operator.
Let me make an example.
class Data{
protected:
int data[3];
public:
Data(){
data[0] = data[1] = data[2] = 0;
}
Data operator+(const Data& other)
{
Data temp = *this;
for(int i=0;i<3;i++){
temp.data[i] += other.data[i]
}
return temp;
}
};
class DataInterited:public Data{
public:
};
/******************Main*****************/
DataInterited d1,d2,d3;
d3 = d1 + d2; //=> This is compile error
This code generate compile error saying,
no match for ‘operator=’ (operand types are ‘DataInterited’ and ‘Data’)
I think I have to implement operator+ for DataInherited so that it return DataInherited instance. But in this way, I cannot avoid code duplication.
Is there any way to make d3=d1+d2; line correct while avoiding duplicating the + operator implementation?
There are a couple of things you need to know.
First, always implement operator+ as a free function in terms of operator+=. It saves code duplication and is optimally efficient.
Second, you had no constructor in DataInherited that could take a Data as its argument. This is important because the result of Data::operator+ is a Data, not a DataInherited.
corrected code:
#include <iostream>
#include <algorithm>
class Data{
protected:
int data[3];
public:
Data(){
data[0] = data[1] = data[2] = 0;
}
Data(const Data& other)
{
std::copy(std::begin(other.data), std::end(other.data), data);
}
Data& operator=(const Data& other)
{
std::copy(std::begin(other.data), std::end(other.data), data);
return *this;
}
Data& operator+=(const Data& other)
{
for(int i=0;i<3;i++){
data[i] += other.data[i];
}
return *this;
}
};
Data operator+(Data left, const Data& right)
{
return left += right;
}
class DataInterited:public Data{
public:
DataInterited(Data d = {})
: Data(std::move(d))
{}
};
using namespace std;
auto main() -> int
{
DataInterited d1,d2,d3;
d3 = d1 + d2; //=> This is no longer a compile error
return 0;
}
Koenig operator forwarding to an increment_by function.
Derived classes can implement their own increment_by overloads if they want different behavior.
SFINAE stuff skipped, so bad types will give hard errors.
class Data{
public:
template<class D, class Rhs>
friend D operator+=(D&& lhs, Rhs&& rhs){
increment_by(lhs,std::forward<Rhs>(rhs));
return std::forward<D>(lhs);
}
template<class Lhs, class Rhs>
friend Lhs operator+(Lhs lhs, Rhs&& rhs){
lhs+=std::forward<Rhs>(rhs);
return std::move(lhs);
}
friend void increment_by(Data& self, Data const&other){
for(int i=0;i<6;i++){
self.data[i] += other.data[i];
}
}
};
Both + and += are template friends and hence the types passed can be derived classes. So type isn't lost,
increment_by needs overiding if derived type needs new behaviour. If not, leave it alone.
live example.
Do not leave the type needlessly. Converting from base to derived basically throws out the point of the derived type.
For example, we have this class:
class my_class
{
public:
friend my_class operator* (const my_class&, int a);
friend my_class operator* (int a, my_class&);
};
my_class operator* (int a, my_class&)
{
// do my_class * a
}
my_class operator* (int a, my_class&)
{
// do a * my_class
}
is it possible to do just one operator* to do what these two do?
Thanks!
You cannot do that. However, you can implement one and simply call it from the other one:
my_class operator *(const my_class &l, int r) {
// implement the actual operator here.
}
my_class operator *(int l, const my_class &r) {
return r * l;
}
(Note that you cannot implement the latter function as part of the class. You have to do it externally. The first function can be implemented as an instance method, because its first argument is of the class type.)
You can implement one by using the other:
my_class operator*(int lhs, const my_class& rhs)
{
return rhs * lhs;
}
if the operation itself is commutative. This is not always the case, so be careful.
There are also libraries to help you with certain operators. If you have
my_class mc, a, b;
a = mc * 1;
b = 1 * mc;
you probably also want to be able to do something like
mc *= 1;
In that case you only implement
my_class& my_class::operator*=( int v );
and you can use Boost.Operators or df.operators to generate the other operators automatically.
Example:
struct my_class
: df::commutative_multipliable< my_class, int >
{
// ...
my_class& operator*=( int v )
{
// ... implement me!
return this;
}
// ...
};
In this example you again only implement one operation and the rest is generated using a common schema.
If I have the following files, I get this error (c2593 in VC9).
If I un-comment the prototype in main.cpp, the error disappears. I need to maintain the same functionality while keeping the class out of main.cpp. How can I do that?
Thanks.
main.cpp:
#include "number.h"
//const Number operator + (const Number & lhs, const Number & rhs);
int main(void)
{
Number n1(2); // n1 = 2
Number n2(9,3); // n2 = 3
Number n3 = n1+n2; // n3 = 5
}
number.h:
struct Number
{
int num;
Number(int n=0,int d=1) {num = n/d;}
operator int() {return num;}
operator double() {return num*1.0;}
};
number.cpp:
#include "Number.h"
const Number operator + (const Number & lhs, const Number & rhs)
{
Number tmp;
tmp.num = lhs.num + rhs.num;
return tmp;
}
Try putting the prototype in the Number header file:
number.h:
struct Number
{
int num;
Number(int n=0,int d=1) {num = n/d;}
operator int() {return num;}
operator double() {return num*1.0;}
};
const Number operator + (const Number & lhs, const Number & rhs);
number.cpp:
#include "Number.h"
const Number operator + (const Number & lhs, const Number & rhs)
{
Number tmp;
tmp.num = lhs.num + rhs.num;
return tmp;
}
main.cpp:
#include "number.h"
int main(void)
{
Number n1(2); // n1 = 2
Number n2(9,3); // n2 = 3
Number n3 = n1+n2; // n3 = 5
}
You never declare operator + in number.h, you only define it in number.cpp - therefore, when you include number.h in main.cpp, it doesn't know where to go to find operator +.
You must put the declaration of operator + in number.h, outside of the class, then define it in number.cpp
That commented line should go in number.h
EDIT: in number.h but as a free function.
One other thing to note with your code before you go back to us with a very similar question: Better remove the operator int and operator double functions. They will cause you major headache. Let's make a few examples:
Number a, b;
1 + b;
// ambiguous: operator+(int, int) or
// operator+(Number, Number) ?
// did you intend to use those for this case?
float x = a;
// ambiguous: from int -> float or
// double -> float ?
In the original situation you had, your addition was ambiguous, because there were operator+(double, double) and operator+(int, int) builtin operators considered and they were equally well. Others solved that problem. But before you start and run into these other problems, better remove the conversion functions and insert explicit functions like asDouble or something similar.
Apart from other's answers to declare operator+ in the header file, I suggest you to have operator+= in your struct as well.
struct Number
{
// your other declarations.
Number& operator+=(const Number& other)
{
this->num += other.num;
return *this;
}
};
const Number operator+(const Number& lhs, const Number& rhs)
{
Number ret(lhs);
ret += rhs;
return ret;
}
This way it is efficient to call x += y; instead of x = x + y;
Personally I like it better to declare the operators inside the class:
struct Number
{
int num;
Number(int n=0,int d=1) {num = n/d;}
operator int() {return num;}
operator double() {return num*1.0;}
Number operator+(const Number &arg) const;
};
and then:
Number Number::operator+(const Number &arg)
{
...
}