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;
Esta representación presenta problemas adicionales que son causados por no separar el recorrido, de la estructura de los datos. Como podrás recordar, para iterar sobre los elementos de la lista, hemos usado un bucle con la siguiente condición :
WHILE data IS VALID DO
Data se inicializó con una llamada a list_getFirst(). El procedimieno de la lista integer int_list_getFirst() regresa un entero (integer), por consecuencia, no existe algo como un "integer no válido", lo cuál podríamos usar para un chequeo de terminación del bucle.
mul(k) div(k) abs()
La operación mul no requiere ninguna precondición. Esto es similar a add y sub. La postcondición es por supuesto res = N*k. La siguiente operació div requiere que k no valga 0 (cero). Consecuentemente, definimos la siguiente precondición : k no igual a 0. La última operación : abs regreas el valor de N si N es positivo o vale 0 o, -N si N es negativo. Nuevamente, no importa que valor tiene N cuando se aplica esta operación. Aquí está su postcondición :
class Complex { attributes: Real real, imaginario methods: :=(Complex c) /* Poner el valor a lo que vale c */ Real realPart() Real imaginaryPart() Complex +(Complex c) Complex -(Complex c) Complex /(Complex c) Complex *(Complex c) }
Escogemos los bien conocidos símbolos de operador "+" para la adición, "-" para la resta, "/" para la división y "*" para la multiplicación al implementar las operaciones correspondientes del TDA Complex. Así, objetos de la clase Complex pueden ser usados del siguiente modo:
Complex c1, c2, c3 c3 := c1 + c2
Podrás notar, que podríamos escribir la instrucción de la adición como sigue :
c3 := c1.+(c2)
Podrías querer remplazar el "+" con "add" para aproximarse a una representación que ya hemos usado. Sin embargo, deberías poder entender que "+" no es otra cosa que un nombre diferente para "add".
class Rectangle inherits from Point { attributes: int _width, // Base del rectángulo _height // Altura del rectángulo methods: setWidth(int newWidth) getWidth() setHeight(int newHeight) getHeight() }
En este ejemplo, definimos un rectángulo por su esquina superior izquierda (las coordenadas tal como se heredaron de Point) y sus dimensiones. Alternativamente, lo podríamos haber definido por su esquina superior izquierda y su esquina inferior derecha.
Añadimos métodos de acceso para la base y la altura del rectángulo.
class Sphere inherits from 3D-Point { attributes: int _radius; methods: setRadius(int newRadius) getRadius() }
Esto es similar a la clase círculo para un espacio en 2a. dimensión. Ahora3D-Point es solamente un Point con una dimensión adicional:
class 3D-Point inherits from Point { attributes: int _z; methods: setZ(int newZ); getZ(); }
Consecuentemente, 3D-Point y Point tienen una relación es-un(a).
move() como se definió en la sección le permite a los objetos de 3a. dimensión moverse a lo largo del eje-X, es decir, en una sola dimensión. Hace esto, al modificar solamente la parte de 2a. dimensión de los objetos de 3a. dimensión. Esta parte de 2a. dimensión está definida por la clase Point heredada directamente o indirectamente por los objetos de 3a. dimensión.
Sin embargo, estas propiedades se identifican en forma única siguiendo la trayectoria hacia arriba desde D hasta A. Así, D puede cambiar las propiedades de A heredadas por B al seguir la trayectoria de herencia a través de B. En forma similar, D puede cambiar las propiedades de A heredadas por C al seguir la trayectoria de herencia a través de C. Consecuentemente, este conflicto de nomenclatura no necesariamente conlleva a error, mientras las trayectorias estén designadas.
void display(const DrawableObject obj);nótese primero, que en C++ los parámetros de funciones o métodos son pasados por valor. Consecuentemente, obj sería una copia del argumento de llamada a función realmente provisto. Esto significa que DrawableObject debe ser una clase de la cuál se pueden crear objetos. Este no es el caso, si DrawableObject es una clase abstracta (tal como sucede cuando print() se define como un método puro.)
Si existe un método virtual print() que está definido por la clase DrawableObject, entonces (como obj es solamente una copia del argumento real) este método es invocado. Este no es el método definido por la clase del argumento real (¡debido a que ya no juega ningún rol significativo !)
T &operator ++() { succ(); return(_current ? _current->data() : (T) 0); }Sin embargo, esto no funciona como estamos asumiendo ahora algo sobre T. Debe ser posible convertirlo a un tipo de valor "NULL".
Durante la iteración, remove() debe comparar el ítem de datos provisto sucesivamente con aquéllos en la lista. Consecuentemente, podría existir una comparación como :
if (data == current->data()) { // se encontró el ítem }
Usamos aquí el operador de ecuación "= =" para comparar ambos ítemes de datos. Como estos ítemes pueden ser de cualquier tipo, pueden ser especialmente objetos de clases definidas por el usuario.
La cuestión es : ¿Cómo se define la "igualdad" para esos tipos nuevos ? Consecuentemente, para permitir a
remove() que trabaje adecuadamente, la lista debería ser usada solamente para tipos que propiamente definan los operadores de comparación (a saber, "= =" y " !="). De otro modo, se usan las comparaciones de "default", lo que llevaría a resultados extraños.
class CountedList : public List { int _count; // El número de elementos ... public: ... virtual void append(const T data) { _count++; // lo incrementa y ... List::append(data); // ... usa el append de la lista } ... }
No todos los métodos pueden ser implementados de esta manera. En algunos métodos, uno debe checar si _count necesita ser alterado o no. Sin embargo, la idea principal es que cada método de la lista es solamente expandido (o especializado) para la lista contada.