Rogue Wave banner
Previous fileTop of documentContentsIndexNext file

13.4 Virtual Functions Inherited From RWCollection

The Smalltalk-like collection classes inherit from the abstract base class RWCollection, which in turn inherits from the abstract base class RWCollectable, described in Section 13.1 and 15. (Thus do we produce collections of collections, but that is another story.)

An abstract base class is a class intended to be inherited by some other class, not used as itself per se. If you think of it as a kind of virtual class, you can easily project the meaning of virtual functions. These virtual functions provide a blueprint of functionality for the derived class. As an abstract base class, RWCollection provides a blueprint for collection classes by declaring various virtual functions, such as insert(), remove(), entries(), and so on.

This section describes the virtual functions inherited by the Smalltalk-like collections. Any of these collections can be expected to understand them.

13.4.1 insert()

You can put a pointer to an object into a collection by using the virtual function insert():

virtual RWCollectable*  insert(RWCollectable*);

This function inserts in the way most natural for the collection. Faced with a stack, it pushes an item onto the stack. Faced with a queue, it appends the item to the queue. In a sorted collection, it inserts the new item so that items before it compare less than itself, items after it compare greater than itself, and items equal compare equal, if duplicates are allowed. See the example in Section 13.2 for an example using insert().

You must always insert pointers to real objects. Since all RWCollection classes need to dereference their contents for some methods such as find(), inserting a zero will cause such methods to crash. If you must store an empty object, we suggest you create and insert a default constructed object of the appropriate type, such as RWCollectable*.

13.4.2 find() and Friends

You can use the following virtual functions to test how many objects a collection contains, and whether it contains a particular object:

virtual RWBoolean       contains(const RWCollectable*) const;
virtual unsigned        entries() const;
virtual RWCollectable*  find(const RWCollectable*) const;
virtual RWBoolean       isEmpty() const;
virtual unsigned        occurrencesOf(const RWCollectable*) const;

The function isEmpty() returns TRUE if the collection contains no objects. The function entries() returns the total number of objects that the collection contains.

The function contains() returns TRUE if the argument is equal to an item within the collection. The meaning of is equal to depends on the collection and the type of object being tested. Hashing collections use the virtual function isEqual() to test for equality, after first hashing the argument to reduce the number of possible candidates to those in one hash bucket. (Here it is important that all items which are isEqual with each other hash to the same value!). Sorted collections search for an item that compares equal to the argument; in other words, an item for which compareTo() returns zero.

The virtual function occurrencesOf() is similar to contains(), but returns the number of items that are equal to the argument.

The virtual function find() returns a pointer to an item that is equal to its argument.

The following example, which builds on the example in Section 13.2, uses find() to find occurrences of Mary in the collection, and occurrencesOf to find the number of times Mary occurs:

#define RW_STD_TYPEDEFS 1
#include <rw/bintree.h>                                       //1
#include <rw/collstr.h>                                       //2
#include <rw/rstream.h>

main(){
// Construct an empty SortedCollection
SortedCollection sc;                                          //3

// Insert some RWCollectableStrings:
sc.insert(new RWCollectableString("George"));                 //4
sc.insert(new RWCollectableString("Mary"));                   //5
sc.insert(new RWCollectableString("Bill"));                   //6
sc.insert(new RWCollectableString("Throkmorton"));            //7
sc.insert(new RWCollectableString("Mary"));                   //8

cout << sc.entries() << "\n";                                 //9

RWCollectableString dummy("Mary");                           //10
RWCollectable* t = sc.find( &dummy );                        //11

if(t){                                                       //12
  if(t->isA() == dummy.isA())                                //13
    cout << *(RWCollectableString*)t << "\n";                //14
  }
else
  cout << "Object not found.\n";                             //15

cout << sc.occurrencesOf(&dummy) << "\n";                    //16

sc.clearAndDestroy();
return 0;
}

Program Output:

5
Mary
2

Here's the line-by-line description:

//1-//7 These lines are from Section 13.2.
//8Insert another instance with the value Mary.
//9This statement prints out 5, the total number of entries in the sorted collection.
//10A throwaway variable dummy is constructed, to be used to test for the occurrences of strings containing Mary.
//11The collection is asked to return a pointer to the first object encountered that compares equal to the argument. A nil pointer (zero) is returned if there is no such object.
//12The pointer is tested to make sure it is not nil.
//13Paranoid check. In this example, it is obvious that the items in the collection must be of type RWCollectableString. In general, it may not be obvious.
//14Because of the results of step 13, the cast to an RWCollectableString pointer is safe. The pointer is then dereferenced and printed.
//15If the pointer t was nil, then an error message would have been printed here.
//16The call to occurrencesOf() returns the number of items that compare equal to its argument. In this case, two items are found, the two occurrences of Mary.

13.4.3 remove() Functions

To search for and remove particular items, you can use the functions remove() and removeAndDestroy():

virtual RWCollectable*  remove(const RWCollectable*);
virtual void            removeAndDestroy(const RWCollectable*);

The function remove() looks for an item that is equal to its argument and removes it from the collection, returning a pointer to it. It returns nil if no item is found.

The function removeAndDestroy() is similar except it deletes the item instead of returning it, using the virtual destructor inherited by all RWCollectable items. You must be careful when using this function that the item was actually allocated off the heap, not the stack, and that it is not shared with another collection.

The following example, which expands on the previous one, demonstrates the use of the virtual function removeAndDestroy():

RWCollectable* oust = sc.remove(&dummy);                     //17
delete oust;                                                 //18

sc.removeAndDestroy(&dummy);                                 //19
//17 Removes the first occurrence of the string containing Mary and returns a pointer to it. This pointer will be nil if there is no such item.
//18Deletes the item, which was originally allocated off the heap. There is no need to check the pointer against nil because the language guarantees that it is always OK to delete a nil pointer.
//19In this statement, the remaining occurrence of Mary is both removed and deleted.

13.4.4 apply() Functions

To efficiently examine the members of a Smalltalk-like collection, use the member function apply():

virtual void apply(RWapplyCollectable ap, void* x);

The first argument, RWapplyCollectable, is a typedef:

typedef void  (*RWapplyCollectable)(RWCollectable*, void*);

In other words, RWapplyCollectable is a pointer to a function with prototype:

void yourApplyFunction(RWCollectable* item, void* x)

where yourApplyFunction is the name of the function. You must supply this function. It will be called for each item in the collection, in whatever order is appropriate for the collection, and passed as a pointer to the item as its first argument. The second argument x is passed through from the call to apply(), and is available for your use. For example, you could use it to hold a handle to a window on which the object is to be drawn.

Note that the apply() functions of the Smalltalk-like collections and the generic collections are similar. (Compare Section 12.3.2.) The difference is in the type of the first argument of the user-supplied function: the Smalltalk-like collections use RWCollectable*, while the generic collections use type*. With both sets of collections, you must be careful that you cast the pointer item to the proper derived class.

The apply-functions generally employ the most efficient method for examining all members of the collection. This is their great advantage. Their disadvantage is that they are slightly clumsy to use, requiring you to supply a separate function[18].

13.4.5 Functions clear() and clearAndDestroy()

To remove all items from the collection, you can use the functions clear() and clearAndDestroy():

virtual voidclear();
virtual voidclearAndDestroy();

The function clearAndDestroy() not only removes the items, but also calls the virtual destructor for each item. You must use this function with care. The function does check to see if the same item occurs more than once in a collection (by building an RWIdentitySet internally), and thereby deletes each item only once. However, it cannot check whether an item is shared between two different collections. You must also be certain that every member of the collection was allocated off the heap.


Previous fileTop of documentContentsIndexNext file
©Copyright 1999, Rogue Wave Software, Inc.
Send mail to report errors or comment on the documentation.