46

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?

3
  • 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. Commented May 13, 2012 at 22:37
  • 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. Commented May 13, 2012 at 22:37
  • 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. Commented May 14, 2012 at 0:25

5 Answers 5

39

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.

Sign up to request clarification or add additional context in comments.

3 Comments

And every C++ compiler on the planet will inline !='s call to ==.
@jthill Be careful: It won't if the operator is not yet defined (e.g. source files).
@Tim, it could if your compiler has LTO.
18

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.

5 Comments

Actually, you only need operator<. Because x == y is logically equivalent to !(x < y) && !(y < x).
@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.
True, it can often be more efficient and more clear. But less maintainable for the same reasons you mentioned above.
@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.
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).
6

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.

1 Comment

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

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.

1 Comment

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

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.