C++ multiple operator overloads for the same operator

23,434

Solution 1

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.)

Solution 2

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.

Solution 3

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.

Share:
23,434

Related videos on Youtube

eladidan
Author by

eladidan

Software Engineer in Quixey, working on large-scale, distributed app crawling

Updated on June 27, 2020

Comments

  • eladidan
    eladidan almost 4 years

    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?

    • David Rodríguez - dribeas
      David Rodríguez - dribeas almost 14 years
      @paercebal: He is implementing the a sum, not an increment. If he was implementing operator+=, then returning a reference would be fine (after modifying the internal state), but a+b is not meant to modify the a, but rather produce a third value that differs from both a and b.
  • sbi
    sbi almost 14 years
    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.
  • Matt Joiner
    Matt Joiner almost 14 years
    I feel bad cluttering your answer with a comment. Spot on.
  • sbi
    sbi almost 14 years
    Oh, and mindlessly copying inline blah MyClass:: into MyClass doesn't seem like you at all. :)
  • Matthieu M.
    Matthieu M. almost 14 years
    +1 for the correct form. However I would probably use Boost.Operators to generate the free-functions for free :)
  • vad
    vad almost 14 years
    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?
  • sbi
    sbi almost 14 years
    @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.
  • Bill
    Bill almost 14 years
    I think operator+ should do: MyClass temp = lhs; temp += rhs; return temp;. Otherwise, if I do: MyClass a = b + c;, then b changes.
  • eladidan
    eladidan almost 14 years
    @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& lhs) and if we overload the "=" operator;
  • sbi
    sbi almost 14 years
    @eladidan: MyClass temp = lhs invokes the copy constructor, not the assignment operator, but otherwise you are right.

Related