views:

136

answers:

6

What is the difference between these two ways of overloading the != operator below. Which is consider better?

Class Test  
{  
...//
private:  
int iTest

public:  
BOOL operator==(const &Test test) const;
BOOL operator!=(const &Test test) const;  
}

BOOL operator==(const &Test test) const  
{  
    return (iTest == test.iTest);  
}    

//overload function 1  
BOOL Test::operator!=(const &Test test) const  
{  
    return !operator==(test);  
}

//overload function 2  
BOOL Test::operator!=(const &Test test) const  
{  
    return (iTest != test.iTest);  
}  

I've just recently seen function 1's syntax for calling a sibling operator function and wonder if writing it that way provides any benefits.

+2  A: 

They will almost certainly compile to the same machine code.

I prefer choice 2, just because I find it awkward to say "operator==". But you could have used

return ! (*this == test)

And IMHO that's also clear and easy to understand.

Larry Gritz
good point. I forgot about just comparing the class. Thanks and much appreciated.
cv3000
+6  A: 

Your first overload ensures that calling != on your type will always provide the opposite of calling == even if your implementation of == would change.

Your second overloaded function does not, since it is possible to provide any implementation for == and change the existing implementation in the future.

If you want to ensure that != will always be the opposite of ==, go with the first (at the cost of an extra function call which may very well become inlined anyway).

Here is a good example. Suppose that you have a class Point2D with fields x and y. If you want to implement ==, you will have to compare on field x and on field y. If you implement != by calling operator==, you have shorter code, and will have one function less to change if you ever moved to a polar representation.

Equality tests and comparisons are always susceptible to maintenance errors as the class fields change. Minimizing the number of methods that directly access state can reduce the risk of errors.

Uri
That's a great point. I never thought about it like that. Thanks.
cv3000
There's also the fact that if you happened to change function 2 to do `return (*this != test);` (since `return !(*this == test);` was suggested for function 1), you'd have a problem because the overloaded `operator!=` function would be calling itself. In other words, using function 1 has the added benefit of avoiding such a debugging headache.
Dustin
+1  A: 

Version #1, while syntacticly ugly IMHO, allows you to change the equality logic in a single place (in the == operator overload). It guarantees the two overloads are always in sync.

Brian Roach
+2  A: 

I can think of many reasons (or perhaps aspects of the same reason) to write it that way. What they all boil down to is: it's DRY.

  • It ensures that two objects are always either == or !=

  • If you decide to change what's in the class, or what's used for equality testing, you only have to change it in one place

I think that conceptually, you really have two different things you're defining here:

  • A definition of "equality" for class Test

  • A useful interface by which people using this class can determine equality of their instances

With method 2, you're doing both ad-hoc. With method 1, you're defining equality in operator==, and providing the rest of the interface via operator!=.

Some languages/libraries take it even further, e.g., in Ruby you can define just <=> to compare ordered objects and mix-in Comparable and get equality, inequalities, and between?.

Ken
Boost has the Operators library which implements for you many arithmetic/comparison operators in terms of a few: http://www.boost.org/doc/libs/1_43_0/libs/utility/operators.htm
Emile Cormier
awesome explaination and greatly appreciated.
cv3000
+1  A: 

In general, the following statement:
return !(*this == object);
allows you to define != in terms of one function. In the world of inheritance, child objects would only need to define operator== in order to use the base class operator!=:

struct Base
{
  virtual bool isEqual(const Base& other) const = 0;
  bool  operator==(const Base& other) const
  {
    return isEqual(other);
  }
  bool  operator!=(const Base& other) const
  {
    return !(*this == other);  // Uses Base::operator==
  }
};

With the above base class, defining operator!= using != would require descendants to implement more methods.

Also, !(*this == other) allows one to define a global, generic function for !=:

template <typename T>
bool operator!=(const T& a, const T& b)
{
  return !(a == b);
}

Although this pattern doesn't provide much for == and !=, the differences are larger when using the relational operators: <, <=, >, >=.

Thomas Matthews
A: 

In general, it is always better to implement related functionality in terms of each other. In case of operators, there are always groups. For example, != can be implemented in terms of ==; post-increment can be implemented in terms of pre-increment; >, <= and >= can be implemented in terms of < (see std::rel_ops in <utility>) etc. If something about the class needs changing, you only need to modify the core operators, and all the rest will automatically be updated to reflect the new behavior.

The general implementation of all the "secondary" operators is always the same, and so there is even a library which automatically provides operators that are defined in terms of a few provided ones. See Boost.Operators

Your example:

#include <boost/operators.hpp>

class Test : boost::equality_comparable<Test, Test>
{
private:
    int iTest;

public:
    bool operator==(const Test& test) const;
    //look, no operator !=
};

int main()
{
    Test a, b;
    a != b; //still works
}
UncleBens