views:

222

answers:

3

I know I can answer this question easily for myself by generatin the code and see if it compiles. But since I couldn't find a similar question, I thought it's knowledge worth sharing. Say I am overloading the + operator for MyClass. Can I overload it multiple times. Different overload for different types. Like this:

class MyClass{
...
inline const MyClass operator+(const MyClass &addend) const {
    cout<<"Adding MyClass+MyClass"<<endl;
    ...//Code for adding MyClass with MyClass
}
inline const MyClass operator+(const int &addend) const {
    cout<<"Adding MyClass+int"<<endl;
    ...//Code for adding MyClass with int
}
...
};
int main(){
    MyClass c1;
    MyClass c2;
    MyClass c3 = c1 + c2; 
    MyClass c4 = c1 + 5;
}
/*Output should be:
  Adding MyClass+MyClass
  Adding MyClass+in*/

The reason I want to do this is that I am building a class that I want to be as optimized as possible. Performance is the biggest concern for me here. So casting and using switch case inside the operator + overloaded function is not an option. I f you'll notice, I made both the overloads inline. Let's assume for a second that the compiler indeed inlines my overloads, then it is predetermined at compile time which code will run, and I save the call to a function (by inlining) + a complicated switch case scenario (in reality, there will be 5+ overloads for + operator), but am still able to write easily read code using basic arithmetic operators. So, will I get the desired behavior?

+7  A: 

Yes.


These operator functions are just ordinary functions with the special names operator@. There's no restriction that they cannot be overloaded. In fact, the << operator used by iostream is an operator with multiple overloads.

KennyTM
I feel bad cluttering your answer with a comment. Spot on.
Matt Joiner
+2  A: 

Yes, you can overload operators like this. But I'm not sure what "switch case" you are referring to. You can live with one overload if you have a converting constructor

class MyClass{
...
// code for creating a MyClass out of an int
MyClass(int n) { ... }
...
inline const MyClass MyClass::operator+(const MyClass &addend) const {
    cout<<"Adding MyClass+MyClass"<<endl;
    ...//Code for adding MyClass with MyClass
}
...
};

No switch is needed at all. This is eligible if "MyClass" logically represents a number.

Notice that you should overload these operators by non-member functions. In your code 5 + c1 would not work, because there is no operator that takes an int as left hand side. The following would work

inline const MyClass operator+(const MyClass &lhs, const MyClass &rhs) {
  // ...
}

Now if you keep the converting constructor you can add the int by either side with minimal code overhead.

Johannes Schaub - litb
Johannes, that implicit converting constructor might not be a good idea. For one, IME implicit conversions usually turn out to be a bad idea sooner or later anyway, but also because eladidan wants to do this because "I am building a class that I want to be as optimized as possible." In that case, overloads are better anyway.
sbi
Oh, and mindlessly copying `inline blah MyClass::` into `MyClass` doesn't seem like you at all. `:)`
sbi
+2  A: 

The canonical form of implementing operator+() is a free function based on operator+=(), which your users will expect when you have +. += changes its left-hand argument and should thus be a member. The + treats its arguments symmetrically, and should thus be a free function.

Something like this should do:

//Beware, brain-compiled code ahead!
class MyClass {
public:
    MyClass& operator+=(const MyClass &rhs) const
    {
      // code for adding MyClass to MyClass
      return *this;
    }
    MyClass& operator+=(int rhs) const
    {
      // code for adding int to MyClass
      return *this;
    }
};


inline MyClass operator+(MyClass lhs, const MyClass& rhs) {
  lhs += rhs;
  return lhs;
}
inline MyClass operator+(MyClass lhs, int rhs) {
  lhs += rhs;
  return lhs;
}
// maybe you need this one, too
inline MyClass operator+(int lhs, const MyClass& rhs) {
  return rhs + lhs; // addition should be commutative
}

(Note that member functions defined with their class' definition are implicitly inline. Also note, that within MyClass, the prefix MyClass:: is either not needed or even wrong.)

sbi
+1 for the correct form. However I would probably use Boost.Operators to generate the free-functions for free :)
Matthieu M.
Very basic qn: Your definition for + requires lhs to be a const whereas the code requires you to write lhs += rhs. It seems to be you either need to change your code or your definition. Am I right?
Anon
@Anon: That was a major blurb of mine. `<hangs_head_in_shame>` I went and fixed it, and took the opportunity to add my standard disclaimer.
sbi
I think operator+ should do: `MyClass temp = lhs; temp += rhs; return temp;`. Otherwise, if I do: `MyClass a = b + c;`, then `b` changes.
Bill
@Bill.Not so. lhs is received byVal. Since we return that shallow copy, then we do not change the original parameter and we don't create any unnecessary instances of MyClass. Your solution is valid only if we receive lhs byref (MyClass
eladidan
@eladidan: `MyClass temp = lhs` invokes the _copy constructor_, not the assignment operator, but otherwise you are right.
sbi