MODULE Integer-List DECLARE TYPE int_list_handle_t; int_list_handle_t int_list_create(); BOOL int_list_append(int_list_handle_t this, int data); INTEGER int_list_getFirst(int_list_handle_t this); INTEGER int_list_getNext(int_list_handle_t this); BOOL int_list_isEmpty(int_list_handle_t this); END Integer-List;
This representation introduces additional problems which are caused by not separating traversal from data structure. As you may recall, to iterate over the elements of the list, we have used a loop statement with the following condition:
WHILE data IS VALID DO
Data was initialized by a call to list_getFirst(). The integer list procedure int_list_getFirst() returns an integer, consequently, there is no such thing like an ``invalid integer'' which we could use for loop termination checking.
mul(k) div(k) abs()
The operation mul does not require any precondition. That's similar to add and sub. The postcondition is of course res = N*k. The next operation div requires k to be not 0 (zero). Consequently, we define the following precondition: k not equal 0. The last operation abs returns the value of N if N is positive or 0 or -N if N is negative. Again it does not matter what value N has when this operation is applied. Here is its postcondition:
class Complex { attributes: Real real, imaginary methods: :=(Complex c) /* Set value to the one of c */ Real realPart() Real imaginaryPart() Complex +(Complex c) Complex -(Complex c) Complex /(Complex c) Complex *(Complex c) }
We choose the well-known operator symbols ``+'' for addition, ``-'' for subtraction, ``/'' for division and ``*'' for multiplication to implement the corresponding operations of the ADT Complex. Thus, objects of class Complex can be used like:
Complex c1, c2, c3 c3 := c1 + c2
You may notice, that we could write the addition statement as follows:
c3 := c1.+(c2)
You may want to replace the ``+'' with ``add'' to come to a representation which we have used so far. However, you should be able to understand that ``+'' is nothing more than a different name for ``add''.
class Rectangle inherits from Point { attributes: int _width, // Width of rectangle _height // Height of rectangle methods: setWidth(int newWidth) getWidth() setHeight(int newHeight) getHeight() }
In this example, we define a rectangle by its upper left corner (coordinates as inherited from Point) and its dimension. Alternatively, we could have defined it by its upper left and lower right corner.
We add access methods for the rectangle's width and height.
class Sphere inherits from 3D-Point { attributes: int _radius; methods: setRadius(int newRadius) getRadius() }
This is similar to the circle class for 2D space. Now, 3D-Point is just a Point with an additional dimension:
class 3D-Point inherits from Point { attributes: int _z; methods: setZ(int newZ); getZ(); }
Consequently, 3D-Point and Point are related with a is-a relationship.
However, these properties are uniquely identified by following the path from D up to A. Thus, D can change properties of A inherited by B by following the inheritance path through B. Similarly, D can change properties of A inheritied by C by following the inheritance path through C. Consequently, this naming conflict does not necessarily lead to an error, as long as the paths are designated.
void display(const DrawableObject obj);First note, that in C++ function or method parameters are passed by value. Consequently, obj would be a copy of the actual provided function call argument. This means, that DrawableObject must be a class from which objects can be created. This is not the case, if DrawableObject is an abstract class (as it is when print() is defined as pure method.)
If there exists a virtual method print() which is defined by class DrawableObject, then (as obj is only a copy of the actual argument) this method is invoked. It is not the method defined by the class of the actual argument (because it does no longer play any significant role!)
T &operator ++() { succ(); return(_current ? _current->data() : (T) 0); }However, this does not function as we now assume something about T. It must be possible to cast it to a kind of ,,NULL`` value.
During the iteration, remove() must compare the provided data item successively with those in the list. Consequently, there might exist a comparison like:
if (data == current->data()) { // found the item }
Here we use the equation operator ,,==`` to compare both data items. As these items can be of any type, they especially can be objects of user defined classes. The question is: How is ,,equality`` defined for those new types? Consequently, to allow remove() to work properly, the list should only be used for types which define the comparison operator (namely, ,,==`` and ,,!=``) properly. Otherwise, default comparisons are used, which might lead to strange results.
class CountedList : public List { int _count; // The number of elements ... public: ... virtual void append(const T data) { _count++; // Increment it and ... List::append(data); // ... use list append } ... }
Not every method can be implemented this way. In some methods, one must check whether _count needs to be altered or not. However, the main idea is, that each list method is just expanded (or specialized) for the counted list.