Correción Taller I. Lista de Chequeo

El objetivo de este primer taller era practicar con los primeros Idioms revisados en clase (Forma canónica de Clase, Conteo de Referencias y Sobre-Carta usando conteo de apuntadores ). Se revisan los siguientes items de el código:
 
  1. Que las clases cumplan con la forma canónica (constructor por defecto, constructor por copia, asignación y destructor)
  2. Que exista una clase manejadora y un cuerpo con conteo de referencias
  3. Que se sobrecargue el operador -> en las clases manejadores del String y de la Persona
  4. Que el main tenga la estructura pedida
  5. Que el código esté completo
  6. Que corra la aplicación sin errores
Algunos de los defectos encontrados en el código son:

1. La siguiente clase no inicializa bien su información. El atributo familiares queda con un valor indefinido despues de su construcción. Si el objeto se crea y seguidamente se destruye, causara un error.
 
  class PersonaRep {
    friend class Persona;
  public:
    PersonaRep( const char* n, const char* t ) {
      nom = String(n);
      tel = String(t);
      count =1;
    }
    ~PersonaRep() {
      delete[] familiares;
    }
  private:
    String nom;
    String tel;
    Persona* familiares;
    int count;
  };
2. Ninguna clase del dominio del modelo en desarrollo puede quedar dependiente de su contexto, o de una interfaz. En el siguiente caso el método es dependiente de cout, lo cual lo haria no utilizable en un ambiente gráfico.
 
 
Persona&
Persona::operator = ( const Persona& p )
{
  p.rep->count++;
  cout << "Referencia " << p.rep->count;
  if( --rep->count <= 0 )
    delete rep;
  rep = p.rep;
  return *this;
  cout << "Referencia " << p.rep->count;
};
En este caso es mejor utilizar cerr o bien un Idiom paa manejo de Errores e información de depuración... OJO REF

3. Los atributos de una clase deben ser privados, por mucho protegidos... El siguiente código es en ejemplo de una clase que no cumple con esta regla
 
 
class StringRep
{
private:
        typedef char *Char_p;
public:
        StringRep(StringRep::Char_p * const r)
        {
                rep = *r;
                *r = NULL;
                count = 1;
        }
        StringRep(const char *s)
        {
                ::strcpy(rep = new char[::strlen(s) + 1],s);
                count = 1;
        }
        ~StringRep()
        {
                delete [] rep;
        }
        char *rep;
        int count;
};
4. El conteo de referencias comienza en 1 en el mecanismo estándar... El siguiente código sería un error
 
 
PersonaRep::PersonaRep()
{
        count = 0;
        numFamiliares = 0;
}
5. La clase Manija (en este caso Persona o String) no debe tener ningun elemento de la representación, solo una referencia a un objeto de su clase cuerpo. El siguiente código sería un error:
class Persona 
{ 
public: 
        ...
private: 
        PersonaRep *rep; 
        Persona * familiares[MAX]; 
}; 
 
6. Se espera que la interfaz prestada por la clase Cuerpo sea la más eficiente para la implementación de la clase Manija. El siguiente es un ejemplo en donde no se cumple esto:
 
 
Persona::Persona(const char *nombre, const char *tel)
{
        String nom(nombre);
        String telf(tel);
        rep = new PersonaRep(nom,telf);
}
En este caso se crean dos objetos String innecesarios, ya que podría tenerse una constructora de PersonaRep que reciba dos const char*.
 
 7. Al hacer un include se realiza siempre con un path relativo y ademas considerando una división entre declaración de la clase en un archivo .h y su definición en un .c. Una sentencia como la siguiente
 
 
// Includes
#include "/usr1/cursos/sistemas/a49401/a49401XX/taller1/string.c"
debe cambiarse a
 
// Includes
#include "string.h"
Habría que dividir el archivo .c para sacar la declaración de la clase a un .h

8. El siguiente código
void
Persona::imprimir() const
/*-----------------------------------------------------------------------
Muestra la informacion de la persona y de sus familiares
-----------------------------------------------------------------------*/
{
    int   i;
    char  cad[100];

    cout << "Nombre : " << ref->nombre.asChar();
    cout << "\tTelefono: " << ref->tel.asChar();
    cout << "\n" << "Familiares: \n";
    for ( i = 0; i < numFamiliares(); i++ ) {
        cout << "Nombre : " << ref->familiares[i]->getNombre().asChar();
        cout << "\tTelefono : " << ref->familiares[i]->getTel().asChar() << "\n";
    }
}
Puede verse mejor como
 
 
void
Persona::imprimir() const
/*-----------------------------------------------------------------------
Muestra la informacion de la persona y de sus familiares
-----------------------------------------------------------------------*/
{
    int   i;
    char  cad[100];

    cout << "Nombre : " << ref->nombre.asChar();
    cout << "\tTelefono: " << ref->tel.asChar();
    cout << "\n" << "Familiares: \n";
    for ( i = 0; i < numFamiliares(); i++ ) {
        ref->familiares[i]->imprimir();
    }
}
Y se utiliza la funcionalidad de cada familiar, el cual también es persona.

9. Métodos no inline no deben ir declarados en el .h de una clase

Algunas de las características encontradas en el código son:

1. Uso de constantes en vez de macros.

Es mejor utilizar
 
 
// --------------------- Declaración de Constantes ----------------------
const int MAX = 20;
que
// --------------------- Declaración de Constantes ----------------------
#define MAX 20
Ya que en el primer caso hay chequeo de tipos.

2. Es indispensable tener alguna documentación  del uso de patrones en las clases, para faciltar la identificación de la estructura. Por ejemplo
 
 
//
// Patron envelope(persona) letter(PersonaRep)
//

class Persona
{
...
Se puede intuir algo sobre la estrutura de clases que sigue a esta linea de documentación.

Los errores encontrados por cuenta son:
 
01 1, 2, incompleto, warning en compilación
02 No esta
03 No hay permiso de lectura
04 No hay permiso de lectura
05 2, 3, 4, 5, 6, no es Sobre-Carta, fallas en ejec.
06 No hay permiso de lectura
07 7, No Sobre-Carta, No Conteo-Refs, No main, warnings en compilación
08 No hay permiso de lectura
09 No hay permiso de lectura de los archivos en taller1
10 No hay permiso de lectura
11 1, 8, Fallas en ejecución
12 No Handle-Body, Info. Duplicada, sin menu, core al final.
13 5, Error de ejecución, 
14 5, 9, Innecesaria clase datos, Error ejecución (cambioNombre)
15 Mal uso idioms, versiones 2 y 3, redeclaración de clases, error de compilación
16 Nada
17 1, 3, 8, No menu. error de ejecución (cambiarNombre)
18 8, Mal uso de Conteo-Referencias (No se actualiza bien la representación). Error en la ejecución (cambiarNombre)
19 7, 8, Error de ejecución (copia)
20 No hay permiso de lectura
21 5, 8, No Sobre-Carta