Diseño y Programación Orientados a
Objetos
1er. Sem 2009
Tarea 4: Diferentes Implementaciones para
Conjuntos
Recomendación: Lea detenidamente la tarea, si algo no lo entiende consulte en clases, si es preciso se incorporarán aclaraciones al final.
Objetivos: A través de esta tarea usted practicará: Herencia en C++, copia profunda de objetos en C++, consideraciones ante presencia de miembros dato tipo puntero.
Desarrolle cada uno de los siguientes pasos:
1) Baje los archivos de la tarea desde aquí.
2) Una forma de proveer distintas implementaciones para una estructura de datos en C es vía el uso de compilación condicional. En esta se usa define una constante para seleccionar la versión que deseamos compilar. Los archivos del directorio conditionalCompilation muestran esta estrategia.
2.1) Los archivos set.h, set.cpp, y testsets.cpp conforman el primer programa. Compile (Ej., g++ -g -o testArray set.cpp testsets.cpp) y corra esta versión.
Luego recompile con la variable de compilación TREE. (Ej., g++ -g -o testTree -DTREE sets.cpp testsets.cpp) Corra esta segunda versión.
2.2) ¿Por qué la versión TREE no funciona?
2.3) Modifique los archivos necesarios (sets.h, sets.cpp posiblemente) de tal manera que la versión TREE funciones correctamente.
3) El ofrecer diferentes implementaciones de una clase o tipo de dato abstracto (ADT) es una situación común en bibliotecas. Una forma de hacerlo es usar una clase base única para proveer la parte común de la interfaz del ADT, y subclases en la que cada una se provee una diferente estructura de dato para su implementación. Los archivos del directorio usingInheritance muestran esta estrategia.
En teoría, uno puede escribir código para manipular
el ADT y éste debería operar igualmente bien en todas las
estructuras de datos. En este caso dos un Arreglo y un Árbol.
testset.cpp contiene ejemplos de tales códigos.
3.1)
Transfiera sus cambios pertinentes del paso 2. Compile el programa
basado en herencia.
3.2 ¿Por qué el programa no compila? Haga la corrección correspondiente.
3.3) Luego corra el programa ¿Por qué este nuevo programa no funciona correctamente?
3.4) Haga los cambios necesarios y los mínimos en testset.cpp
para que funcione correctamente.
Ponga lo siguiente en su directorio a enviar con su solución:
1) Su versión modificada de los archivos bajo ambos
directorios. No incluya ejecutables. No cambie los nombres de
los archivos.
2) Un archivo RESPUESTAS.TXT con sus
respuestas a la pregunta del paso 2.2, 3.2, y 3.3.
Aspectos a tener en cuenta
Acceso a Miembros Protected
Los miembros protected
de una clase son accesibles para las operaciones de las clases
derivadas.
Esto significa que los métodos sólo pueden
acceder a variables protected de objetos de su misma clase.
Veamos
un ejemplo:
class Set
{
......
protected:
int size;
};
class TreeSet: public Set
{
.....
private:
....
void
copyMembers(Set& into) const;
};
void
TreeSet::copyMembers(Set& into) const
{
into.size=0; // PROBLEMA PORQUE NO TENEMOS ACCESO A
INTO.SIZE
.....
}
En este ejemplo, no
tenemos acceso a into.size ya que es un miembro protegido de posiblemente otra
clase (que herede de Set). Durante la ejecución, podría tratarse de un objeto
ArraySet (que es otra clase derivada de Set ). El lenguaje niega
el acceso por no garantizar que se trata de un objeto de la misma clase.
En
contraste no hay problemas en:
void TreeSet::copyMembers(Set&
into) const
{
int original = size;
.....
}
Es OK porque estamos accediendo al size del mismo
objeto (luego de la misma clase TreeSet).
Tampoco hay
problemas en:
TreeSet::TreeSet(const TreeSet& s)
{
size =s.size;
root=0;
s.copyMembers(*this);
}
Porque estamos accediendo al campo
protegido de s que también es TreeSet.
Constructor Copia
En C++, definición de una nueva
variable, como en:
Set s1 = s;
equivale a la definición
Set
s1(s); // A
y no a lo que se podría pensar:
Set
s1; s1=s; //B
La gran diferencia entre ambas es
que en A se invoca al constructor de copia
Set (const Set&
s);
mientras que en B se llama al constructor elemental (o sin
parámetros) y luego al operador asignación. Como la verdadera
interpretación dada por el compilador corresponde a A, es preciso
que se implemente el constructor de copia si queremos que esta
definición funcione bien en todos los casos, incluso cuando hay
punteros involucrados, en los otros casos el constructor de copia por
defecto funciona bien como ocurre con el caso de arreglo.
Resultado
de lo anterior considere en su tarea implementar este
constructor.
En General se recomienda la siguiente regla: "Si
por alguna razón usted debe implementar el operador de asignación,
también implemente el constructor de copia y el destructor" En
general si usted sospecha que requiere uno de ellos, lo más seguro
es que requerirá los otros dos también.
Si hay dudas
escriban.... además de la clase, el correo es otro medio para
discutir los tópicos del ramo.