3.13 COMPARING OBJECTS


3.13 COMPARING OBJECTS

Our goal in this section is to talk about comparing objects at a high level and to provide forward pointers to where the reader can find more detailed discussion on the issues involved.

The basic issues in object comparison relate to

  • what can be compared; and

  • how to compare.

Given the following two classes

      class Apple          { class Orange {           Taste taste;         Taste taste;           Size size;           Size size;           Weight wt;           Weight wt;           // ...               // ...           };                }; 

it makes no sense to compare apples with oranges in most cases in real life.[15] However, there can be genuine programming needs for comparing apples with apples and oranges with oranges for the purpose of, say, grading them on the basis of either taste, or size, or weight, or any combination of these and other attributes.

It should be obvious to the reader that there is no unique way to compare class type objects, unlike what can be done with primitive types such as integers. In some situations, weight may be irrelevant for comparing apples, and, in others, it may play a most important role. So it falls on the programmer to tell the system how to compare two objects of the same class. When supplying a criterion for comparing objects, the programmer has to bear in mind that there are two kinds of comparisons that one can make for class type objects:

  • We may wish to know whether or not two objects are identical on the basis of equal values for one or more of the data members. The result of such a comparison is either true or false.

  • Or, we may wish to know whether one object is smaller than, equal to, or greater than another object, again on the basis of the values for one or more data members of the objects involved. Obviously, a function that carries out such a comparison must be capable of returning at least three different symbols, say, 1 when object A is less than object B, 0 when object A is equal to object B, and +1 when object A is greater than object B.

In C++, the first kind of comparison is yielded typically by the ‘==’ operator. The programmer has to overload this operator for a given class. It's the overload definition that tells the system that two apples will be deemed to be identical as long as their sizes are the same, regardless of the other attributes. Operator overloading in C++ is discussed in Chapter 12. As discussed in Section 4.3.3, the string type supplied by the C++ Standard Library already comes with an overload definition for the ‘==’ operator. Two strings are declared identical by this operator if they are composed of identical character sequences.

The second type of comparison in C++ is implemented by defining an appropriate comparison function that returns the three values needed. For example, as reported in Section 4.3.3, the string class of the C++ Standard Library comes with a threevalued function compare() that can be invoked to determine whether one string is less than, equal to, or greater than another string; the comparison is typically established on the basis of the ASCII codes associated with the characters.

Object comparisons in C++ are also needed by the various sort functions that come with the C++ container classes. As discussed in Chapter 12 on operator overloading, the comparison function needed by a sorting algorithm can be supplied either in the form of a function object or by overloading directly the ‘<’ operator.

Our discussion so far on object comparison has been centered primarily on a comparison of two objects on the basis of their content, meaning on the basis of the values of one or more the data members of the objects. Java adds an additional twist to this—it allows object comparisons on the basis of equality of reference. Two objects are equal on the basis of equality of reference if they are the same object in the memory. This kind of a comparison can also be carried out in C++ by comparing the memory addresses of the two objects.

In Java, comparison of two objects on the basis of equality of reference is carried out by the ‘==’ operator. And a comparison on the basis of content can be carried out by a programmer-supplied definition for the equals() method that every class in Java inherits from the root class Object. A frequent source of confusion for beginning Java programmers is the meaning of the ’==’ operator vis-à-vis the role of the function equals(). Say, we are given a class X:

      class X {          int p;          X( int m ) { p = m; }          // ...      } 

and the following statements

      X x1 = new X( 10 );      X x2 = x1;      x1 == x2; // true 

Since both x1 and x2 will be holding references to one and the same object, the comparison in the third statement above will return true.[16] On the other hand, the comparison in the third statement below

      X x1 = new X( 10 );      X x2 = new X( 10 );      x1 == x2; // false 

will return a false simply because x1 and x2 are now holding references to two distinct objects—objects located at two different places in the memory.

What's interesting is that, assuming we do not supply our own override definition for equals that X inherits from Object, comparisons using equals behave in exactly the same manner as comparisons using ‘==:

      X x1 = new X( 10 );      X x2 = x1;      x1.equals( x2 ); // true      X x3 = new X( 10 );      x1.equals( x3 ); // false 

That's because for the root class Object both the ‘==’ operator and the equals method are defined to do the same thing—check for equality of reference. But, being a Java operator, while ‘==’ cannot be overridden, the method equals can.

The class X below has its own override definition for the method equals in line (A) that compares two X objects on the basis of the values of the data member p. So even though the two X objects constructed in lines (B) and (C) are very different, the equality test in line (D) reports them to be equal objects.

 
//EqualityTest.java class X { int p; int q; X( int m, int n ) { p = m; q = n; } boolean equals ( X other ) { return p == other.p; } //(A) } class Test { public static void main( String[] args ) { X x1 = new X( 10, 100 ); // x1 and x2 //(B) X x2 = new X( 10, 10000 ); // look very different //(C) System. out. println( x1. equals( x2 ) ); // true //(D) } }

As mentioned in Chapter 4, the String class in Java already comes with an override definition for the equals method that compares strings on the basis of content.

The Java platform also uses the notion of natural ordering for comparing class type objects. Some of the container classes in the Java Collections Framework discussed in Chapter 5 store objects according to their natural order, unless instructed otherwise by the programmer.

The objects of a Java class exhibit natural ordering if the class has implemented the java.lang.Comparable interface. Such a class must provide an implementation for the compareTo method—referred to as the class's natural comparison method—that can then be used by the algorithms and the data structures for comparing data objects. The compareTo method must return a negative integer, a zero, or a positive integer if the object on which it is invoked is less than, equal to, or greater than the argument object.

It is strongly recommended that a class's natural ordering as dictated by the implementation of the compareTo method be consistent with equals. This consistency is achieved if and only if e1.compareTo( (Object) e2 ) == 0 has the same boolean value as e1.equals ( (Object) e2 ) for every pair of objects e1 and e2 of the class. Lack of this consistency could elicit strange behavior from the data structures that need to compare objects.

Many of the system supplied classes in Java possess natural ordering. These includeString, Integer, Float, Double, Date, File and many others. For the String class, the natural order is lexicographic; it is chronological for the Date class; lexicographic on the pathname for the File class, and so on.

[15]This does not mean that OO forbids you to compare apples with oranges. If there is a legitimate need to carry out what appear to be cross-class comparisons, we could derive the classes Apple and Orange from a common root class Fruit and equip the root class with a suitable comparator function.

[16]It is interesting to note that for C++ the comparison made in the third statement below

      X x1;      X x2 = x1;      x1 == x2;                        // true 
will also return true, but for a reason that is entirely different from that for Java. In C++, the second statement will cause the copy constructor of X to be invoked to copy over the data members of x1 into the memory locations reserved for the data members of x2. The objects x1 and x2 will be two different objects, in the sense of residing at two different locations in the memory, even though their data members will have the same values. If overloaded in the usual manner, the operator ‘==’ in C++ will check for the identity of the two objects on the basis of equality of content. Copy constructors in C++ are discussed in Chapter 11 and operator overloading in Chapter 12.




Programming With Objects[c] A Comparative Presentation of Object-Oriented Programming With C++ and Java
Programming with Objects: A Comparative Presentation of Object Oriented Programming with C++ and Java
ISBN: 0471268526
EAN: 2147483647
Year: 2005
Pages: 273
Authors: Avinash Kak

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net