Comparison operator overloading

68,103

Solution 1

The second implementation has the notable constraint that == will always be the boolean opposite of !=. This is probably what you want, and it makes your code easier to maintain because you only have to change one implementation to keep the two in sync.

Solution 2

You should always use what you have when overloading comparison operators. The only two you should need to define are operator== and operator<. The rest you can write in terms of these two. It's less error-prone, as if you have a mistake, it's only in one place.

One of the main features of OOP is code reusability. If you've already written the code, why write it again? Stick to what you have, and you'll only have one thing to test.

It's rather like declaring a constant, and then using it in several spots throughout your file.

Solution 3

Implementation 2 is better because it makes use of the already defined operator==. Also those operator functions should be const because they don't modify the object.

Solution 4

None of the above.

I wish I could find the paper that really goes over this in detail but I can't recall the name.

Your comparison operations should be external. Your interface should be sufficient to finding the state of an object and the state of the object should be dictating comparison. It should be possible to write "equals" outside of your class, and thus any comparison really, and that being possible...you want to.

Solution 5

In general, implementation 2 is better for many reasons. First of all, you don't write (almost) duplicate code. If you need to change it (because the class has grown or there has been a bug), again with implementation 2 you change only 1 place. That is, implementation 2 makes your code more consistent and less error prone.

Share:
68,103

Related videos on Youtube

blaze
Author by

blaze

Goodbye galaxy!

Updated on July 09, 2022

Comments

  • blaze
    blaze almost 2 years

    Which is best practice (in this case):

    bool Foo::operator==(const Foo& other) {
      return bar == other.bar;
    }
    
    // Implementation 1
    bool Foo::operator!=(const Foo& other) {
      return bar != other.bar
    }
    
    // Implementation 2
    bool Foo::operator!=(const Foo& other) {
      return !(*this == other);
    }
    

    For operators like >, <, <=, >= I would go with implementation 2 when possible. However, for != I think implementation 1 is better since another method call is not made, is this correct?

    • Flexo
      Flexo almost 12 years
      I'd write it the most natural way to express it correctly. The compiler is probably going to do a good job of compiling it which ever way you pick.
    • blaze
      blaze almost 12 years
      Ok thanks. As a side note, I know that if the == is way too complex, then implementation 2 would be better, but that is another case.
    • David Rodríguez - dribeas
      David Rodríguez - dribeas almost 12 years
      You should add a const to each one of the functions. Also consider using free functions rather than member functions, as the former are symmetric with respect to types and conversions where the latter aren't. This is more important if your type can be implicitly converted from other types.
  • jthill
    jthill almost 12 years
    And every C++ compiler on the planet will inline !='s call to ==.
  • David Rodríguez - dribeas
    David Rodríguez - dribeas almost 12 years
    This is not always true. There can be designs in which you don't want to grant access to all of the state. Then again, you can always grant access to a free function through friendship.
  • Tim
    Tim almost 10 years
    @jthill Be careful: It won't if the operator is not yet defined (e.g. source files).
  • zneak
    zneak almost 10 years
    @Tim, it could if your compiler has LTO.
  • mdenton8
    mdenton8 over 8 years
    Actually, you only need operator<. Because x == y is logically equivalent to !(x < y) && !(y < x).
  • chris
    chris over 8 years
    @mdenton8, Sure, but it's idiomatic to define both operator< and operator== from scratch if you want all of the comparison operators. Some C++ STL algorithms and containers will use operator== for equality and some will use operator< in the way you described. It's true that if they do different things, you might have some surprising results when using certain algorithms.
  • mdenton8
    mdenton8 over 8 years
    True, it can often be more efficient and more clear. But less maintainable for the same reasons you mentioned above.
  • chris
    chris over 8 years
    @mdenton8, Well, I've been trying to think of why it's idiomatic to implement both from scratch, but I can only find that advice, not the reasoning behind it. Of course you could have a class that defines equality differently than equivalence (which you'd get using operator<), and that class would need both. However, I can think of only one reason in general that they would be separate and that is that implementing operator== in terms of operator< would cause two full comparisons instead of one. I can't wait for default comparison operators, but they can quickly become very limited.
  • freakish
    freakish over 8 years
    Actually you are all wrong. The big assumption you make is that < expresses a linear order. But that might not be the case. For example consider people ordered by genealogical descendancy. This is not a linear order, some people are not comparable, i.e. for me X and my brother Y neither X<Y nor X>Y holds, i.e. they both return false. So generally X<Y is not equivalent to !(X>=Y) and X==Y is not equivalent to !(X<Y) && !(Y<X).
  • MatrixManAtYrService
    MatrixManAtYrService about 8 years
    I can't be sure what precisely about my setup caused this (boost.optional, maybe) but I got a boatload of errors like stl_algobase.h:808:22: error: no match for 'operator==' until I declared the functions const Thanks for pointing this out.