views:

197

answers:

5

Hi i am facing a problem with the code below which is run on VS c++ 2008.How to write the function definition for operator + when you have a statement to be overloaded as follows

class Distance
{

private:

int feet,inches;

};

main......

Distance Obj, Obj1(2, 2);

Obj = 3 + Obj1; // this line here

Obj1+3 is easy but how in this one compiler will come to know that it has to do overloading. Suppose I have to add the value 3 to the data member "feet" of Obj1.

Thanks

+3  A: 

You need to write a free function (outside the class):

Distance operator+(int lhs, const Distance& rhs)
{
  return ...;
}

If ... needs to use private members of Distance then make it a friend in Distance.

class Distance
{
  ...
  friend Distance operator+(int lhs, const Distance& rhs);
};

Finally, if you want to be able to + with Distance on the left-hand side, just define another operator+ overload as above, but with Distance as the first argument.

All this said, I would avoid doing what you appear to be doing. As a user of your Distance class, I don't know whether what you are doing would add 3 feet, 3 inches, or 3 meters. If you aren't going to use SI units (meters) then you shouldn't allow addition with non-Distance values.

Peter Alexander
Beat me to it! :)
Drew Hall
Even if you _are_ using SI units, you should usually disallow weakly-typed addition for consistency with multiplication. `Distance(3) * Distance(4)` and `Distance(3) * 4` both make sense but have different meanings. You can't afford to have an implicit conversion from int to Distance there.
MSalters
Hmm? If `Distance` is in meters then surely they both evaluate to `Distance(12)`?
Peter Alexander
@ Peter Alexander:Thanks
Salar
error C2511: 'Distance Distance::operator +(int,const Distance which has been declared inside class Distance.Only i have this error left.
Salar
Are you sure that you put the definition of `operator+` *outside* the class? The first bit is outside the class, the second (friend) bit is inside.
Peter Alexander
Yes i am sure that i defined it outside the class' body and declared it inside the class.
Salar
+1  A: 

Generally an operator of that form would be declared as:

Distance operator+(int lhs, const Distance& rhs) {
  // Assuming the int value represents feet
  return Distance(rhs.feet + lhs, rhs.inches);
}

You'd probably also want to define the symmetric:

Distance operator+(const Distance& lhs, int rhs) {
  // Assuming the int value represents feet
  return Distance(lhs.feet + rhs, lhs.inches);
}

Also, I suggest you heed the advice of James McNellis--your job will be simplified if you just have one member representing lengths in a single unit.

Drew Hall
Any particular reason for the second function being a free function rather than a member function of Distance class? Just for symmetry?
JBRWilkinson
class Distance{private:int feet,inches; Distance():feet(0),inches(0) {}Distance( int a,int b ):feet(a),inches(b){}Distance operator+( int int main(){Distance c7,c2(2,2);c7=3+c2;cout<<"c7.feet is :"<<c7.feet<<endl;cout<<"c7.inches is :"<<c7.inches<<endl;}Well i tried nd it did'nt work well.
Salar
@Drew Hall :error C2511: 'Distance Distance::operator +(int,const Distance which has been declared inside class Distance.Only i have this error left nd i am sure that i defined function's body outside class.
Salar
@Salar: You've defined it outside the class, but it's still a member function of the class (that's what the Distance:: prefix means). You need to define it as a free function (non-member, thus no Distance:: prefix) outside of the class. In fact, just copy and paste the code I gave above after your class definition (and remember to write "inline" in front of each function) and it should work.
Drew Hall
Yes it worked but i really did'nt get the logic behind it.Operator overloading function should be part of the class?How would it come to know that it has to overload the operator...
Salar
@Salar: When the compiler sees a + b, it tries to translate it two different ways: a.operator+(b), and operator+(a,b). If both are provided, you get an error claiming the resolution is ambiguous. Otherwise, it happily uses either one. The advantage to defining (non-assignment) arithmetic operators outside the class is that implicit type conversions can then work on both sides of the operator, whereas with the member version, they can only be applied to the right hand side.
Drew Hall
+6  A: 

Several answers now suggest using a non-member operator+ overload to allow "addition" of Distance and int objects. This doesn't really make sense: what does it mean to add a Distance, which has a unit, to an int, which does not?

However, it does make sense to add two Distance objects together. If you have one distance of two feet and add another distance of three feet to it, you get a distance of five feet. This makes sense.

You can accomplish this by overloading operator+ between two Distance objects (for simplicity, I've assumed that your Distance only has a single field containing inches. In a real-world application, you wouldn't want to have separate fields for inches and feet. You'd probably want to use an SI unit, like meters, but that depends on the application and is entirely up to you):

Distance operator+(const Distance& lhs, const Distance& rhs)
{
    return Distance(lhs.inches + rhs.inches);
}

This doesn't help you, though, if you want to be able to do something along the lines of

Distance d;
d = d + 42; // assume 42 has the same units as a Distance object has

In order to get this to make sense, you can use a converting constructor:

struct Distance
{
    Distance(int in = 0) : inches(in) { }
private:
    int inches;
};

The constructor here is a converting constructor because it is not explicit and can be called with a single argument. It allows a single int (or a value that is implicitly convertible to an int) to be converted to a Distance object. This allows you to write

Distance d;
d = d + 42;

Why is this different from using an operator+ overload that takes a Distance and an int argument? Simple: it forces the conversion from int to Distance to take place before the addition, so the actual addition doesn't have to care about its operands: it simply adds two distances together and lets the Distance constructors deal with any conversions that need to take place.

James McNellis
@James McNellis: How does this change if for whatever reasons this constructor needs to be explicit? Does it indicate a design flaw?
Chubsdad
@chubsdad: Well, if the constructor is `explicit` then it is not a converting constructor (a converting constructor is, by definition, a constructor that is not explicit and that can be called with a single argument). If the constructor were explicit, it would not be considered as a user-defined conversion and you would not be able to perform `d + 42`. You would need to perform `d + Distance(42)`. There are scenarios under which converting constructors are useful, and this is potentially one of them. I don't think the presence of a converting constructor immediately indicates a design flaw.
James McNellis
Even if you rule out `3 + Distance(4)`, you still need similar overloading for `3 * Distance(4)`
MSalters
@MSalters: If I understand your comment correctly, you are saying that my converting constructor suggestion falls apart if you need other operators (like `operator*`). I completely agree (I'll try to revisit this answer in the morning to discuss that, unless someone beats me to it; I don't know what I'm doing answering questions at 3am anyway... ;-).
James McNellis
@James McNellis: One good thing with this approach is that it eliminates the need for a friend function declaration and namespace pollution also!!
Chubsdad
@James McNellis : Yup, `operator*(Distance, Distance)` will return an `Area`. Hence the need for an `Distance operator*(int, Distance)`; an implict conversion int->Distance won't do.
MSalters
@James McNellis:Thanks
Salar
+3  A: 

Apart from overloading the + operator taking two Distance objects you should avoid overloading operator+(const Distance &, int) as pointed out in other answers. It's better to define some constants like:

const Distance feet(1,0);
const Distance inch(0,1);

and also overload the operator*(int, const Distance &) so that you then can write:

Distance dist = 3 * feet + 5 * inch;
Distance dist2 = dist + 2 * feet;

which is more readable.

Andre Holzner
@Andre Holzner:Thanks
Salar
+1  A: 

While not exactly an answer I'd like to point out that Boost::Units probably solves the OPs original problem throughoutly.

Still it's useful to understand the mechanisms involved.

Fabio Fracassi
@Fabio Fracassi:Thanks
Salar