Pasar 'this' como parametro

Iniciado por DvNe, 2 Abril 2014, 21:44 PM

0 Miembros y 1 Visitante están viendo este tema.

DvNe

Buenas,

Estoy realizando una clase Tarjeta, la cual tiene el siguiente constructor:
Código (cpp) [Seleccionar]

#include "tarjeta.h"
#include "usuario.h"

using namespace std;

Tarjeta::Tarjeta (const Numero& numero, const Usuario &user, const Fecha& caducidad) : numero_(numero), user_(&user), caducidad_(caducidad) {
  Fecha f_actual;
  titular_ = user.nombre() + " " + user.apellidos();

  if (caducidad_ < f_actual)
    throw(Tarjeta::Caducada(caducidad_));
  //(&user).es_titular_de(*this);
}


Por otro lado, aquí tenemos la cabecera tarjeta.h

Código (cpp) [Seleccionar]
#ifndef _TARJETA_H_
#define _TARJETA_H_

#include "fecha.h"
#include "cadena.h"
#include "numero.h"

class Usuario;

class Tarjeta {
public:
  class Caducada {
  public:
    Caducada (const Fecha& f) : fecha_(f) {}
    Fecha cuando() const { return fecha_; }
  private:
    Fecha fecha_;
  };

  Tarjeta (const Numero&, const Usuario&, const Fecha&);
 
  Numero numero() const { return numero_; }
  Fecha caducidad() const { return caducidad_; }
  Cadena titular_facial() const { return titular_; }
  const Usuario* titular() const { return user_; }
  void anula_titular();

  friend std::ostream& operator << (std::ostream&, const Tarjeta&);
private:
  Numero numero_; //Numero de identificacion de la tarjeta
  const Usuario * const user_; //Puntero constante al usuario dueño
  Fecha caducidad_; //Fecha de caducidad
  Cadena titular_; // Nombre y apellidos del dueño

  Tarjeta (const Tarjeta&);//Deshabilitamos copia de una tarjeta
};
#endif


Y por otro lado, los archivos de USUARIO:

Código (cpp) [Seleccionar]
#ifndef _USUARIO_H_
#define _USUARIO_H_

#include "cadena.h"
#include "clave.h"
#include "articulo.h"
#include "tarjeta.h"
#include "numero.h"

#include <sstream> //ostringstream
#include <map>
#include <set>
using std::map;
using std::set;

class Tarjeta;

class Usuario {
public:
  //CONSTRUCTOR Y DESTRUCTOR
  Usuario (const Cadena&, const Cadena&, const Cadena&, const Cadena&, const char*);
  //~Usuario();
 
  class Id_duplicado {
  public:
    Id_duplicado (const Cadena& id) : id_duplicado(id) {}
    const Cadena idd() { return id_duplicado; }
  private:
    const Cadena id_duplicado;
  };
  //FUNCIONES OBSERVADORAS
  Cadena id() const { return identificador_; }
  Cadena nombre() const { return nombre_; }
  Cadena apellidos() const { return apellidos_; }
  Cadena direccion() const { return direccion_; }
  Cadena password() const { return password_.clave(); }

  //FUNCIONES CON TARJETAS
  typedef map<Numero, Tarjeta*> Tarjetas;
  void es_titular_de(Tarjeta&);
  /*
 
  void no_es_titular_de(Tarjeta&);
  const Tarjetas& tarjetas() const;
  */
 
  //FUNCIONES CON LOS ARTICULOS
  typedef map<Articulo*, unsigned> Articulos;
  void compra(Articulo&, unsigned);
  const Articulos& compra() const { return articulos_; }
  size_t n_articulos() const { return articulos_.size(); }

  //SOBRECARGA OPERADOR
  friend std::ostream& operator << (std::ostream&, const Usuario&);
 
private:
  Cadena identificador_;
  Cadena nombre_;
  Cadena apellidos_;
  Cadena direccion_;
  Clave password_;
  /* 
      Tarjetas tarjetas_;*/
  Articulos articulos_;

  static set<Cadena> identificadores;
  bool IdValido() const throw(Usuario::Id_duplicado);
  Usuario (const Usuario&); //Deshabilitamos la copia de un usuario
};

void mostrar_carro(std::ostringstream&, const Usuario&);
//inline const Tarjetas& tarjetas() const { return tarjetas_; }

#endif


El problema es que cada vez que se crea una tarjeta, su constructor, debe asociar al usuario dueño la existencia de dicha tarjeta con la función void es_titular_de(Tarjeta&);

Pero no sé hacerlo ya que me sale un error diciendo:

pasar 'const Usuario' como el argumento 'this' de 'void Usuario::es_titular_de(Tarjeta&)' descarta a los calificadores

ivancea96

#1
Pon un ejemplo donde falle. Un fragmento de código que falla ayudaría bastante.

amchacon

No metas clases dentro de otras, aunque sintacticamente se puede (usando el operador de ambito "::") no es adecuado ni una buena costumbre. Te vas a llevar muchos dolores de cabeza innecesariamente.

Defina la clase fuera:

Código (cpp) [Seleccionar]
#include "fecha.h"
#include "cadena.h"
#include "numero.h"

class Usuario;

class Caducada
{
public:
    Caducada (const Fecha& f) : fecha_(f) {}
    Fecha cuando() const
    {
        return fecha_;
    }
private:
    Fecha fecha_;
};

class Tarjeta
{
public:

    Tarjeta (const Numero&, const Usuario&, const Fecha&);

    Numero numero() const
    {
        return numero_;
    }
    Fecha caducidad() const
    {
        return caducidad_;
    }
    Cadena titular_facial() const
    {
        return titular_;
    }
    const Usuario* titular() const
    {
        return user_;
    }
    void anula_titular();

    friend std::ostream& operator << (std::ostream&, const Tarjeta&);
private:
    Numero numero_; //Numero de identificacion de la tarjeta
    const Usuario * const user_; //Puntero constante al usuario dueño
    Fecha caducidad_; //Fecha de caducidad
    Cadena titular_; // Nombre y apellidos del dueño

    Tarjeta (const Tarjeta&);//Deshabilitamos copia de una tarjeta
};
#endif
Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar

DvNe

Código (cpp) [Seleccionar]
Usuario* pU;
pU = new Usuario("pperez","Perico","Perez Palotes","13 Rue del Percebe","pedrofueacomprarpan");
    try {
const Tarjeta t(numer,*pU,Fecha(6,5,2020));
    }  catch (Tarjeta::Caducada e) {
cerr << "Excepcion: Tarjeta caducada " << e.cuando() <<endl;
    }

ivancea96

#4
Prueba a poner, en vez de:
Código (cpp) [Seleccionar]
(&user).es_titular_de(*this);

Pones:
Código (cpp) [Seleccionar]
user.es_titular_de(*this);

Sinó, prueba a declarar "es_titular_de()" como const. (Siempre que realmente sea const, claro)

eferion

Código (cpp) [Seleccionar]

Tarjeta::Tarjeta (const Numero& numero, const Usuario &user, const Fecha& caducidad) : numero_(numero), user_(&user), caducidad_(caducidad) {
  Fecha f_actual;
  titular_ = user.nombre() + " " + user.apellidos();

  if (caducidad_ < f_actual)
    throw(Tarjeta::Caducada(caducidad_));
  //(&user).es_titular_de(*this);
}


es decir, user tiene el modificador const.

La llamada es_titular_de tiene la firma:

Código (cpp) [Seleccionar]
void es_titular_de(Tarjeta&)

Es decir, no tiene el modificador const.

Cuando tu declaras una instancia como const quiere decir que, desde ese momento, no se puede modificar su estado. Esto implica que no se permiten las llamadas a métodos no const para dicha instancia.

Hasta ahí tu error. Luego hay varias cosas que no entiendo:

1. es_titular_de no tiene sentido que retorne void, es como preguntar a alguien la hora por la calle, que el otro la vea y no te responda... si lo que hace la implementación es imprimir por pantalla el resultado, mi consejo es que lo saques fuera de la clase.

Las razones son sencillas:

* La clase que contiene la función se llama Usuario, luego se presupone que su misión es gestionar la información de un usuario y no encargarse además de imprimir sus datos por pantalla, guardar los datos en un fichero y llamar a su novia en los aniversarios... responsabilidades definidas.

* Concentrar múltiples responsabilidades conlleva concentrar el código, lo que dificulta las tareas de depuración.

* El código se oscurece porque las estructuras de datos tienen a diluirse.

Tiene más sentido que la función luzca tal que

Código (cpp) [Seleccionar]
bool es_titular_de( const Tarjeta& ) const;

2. Tiene sentido crear instancias de "Caducada" con el constructor por defecto??

Entiendo que no, pero sin embargo, al no definir el constructor por defecto en la sección "private" se crea un constructor por defecto. Con poner solo la declaración en el archivo de cabecera vale. En C++11 también puedes impedir el uso del constructor por defecto de la siguiente forma:

Código (cpp) [Seleccionar]

class Caducada
{
  public:
    Caducada( ) = delete;
};


Lo mismo es aplicable a las clases Tarjeta y Usuario.

3. Esta línea

Código (cpp) [Seleccionar]
const Usuario * const user_; //Puntero constante al usuario dueño

te puede dar más problemas que alegrías. Sobretodo porque...

Código (cpp) [Seleccionar]
const Usuario* titular() const { return user_; }

Es decir, no hay ningún problema en que se modifiquen los datos del usuario.

Personalmente, dado que no hace falta que la clase cree el puntero, casi es más limpio pasar y almacenar una referencia, así evitas la "tentación" de poner un delete en un momento dado. Además, pasar clases por referencia te asegura de que la clase existe, ya que no se puede pasar un puntero a null por referencia.

Código (cpp) [Seleccionar]

class Tarjeta
{
  public:

    Tarjeta (const Numero& numero, const Usuario& usuario, const Fecha& fecha )
      : user_( usuario )
    { }

    Usuario& titular() const
    { return user_; }

private:

  Usuario& user_;
};



4.

Código (cpp) [Seleccionar]
throw(Tarjeta::Caducada(caducidad_));

No es buena idea lanzar una excepción que no herede de std::exception. El motivo es que, si no heredan de std::exception, la captura por defecto es catch( ... ) y en este caso pierdes toda la información acerca de la excepción. Además, siempre es recomendable que la excepción incluya un texto descriptivo... es útil en sistemas más complejos para seguir la traza del fallo.

5.

Código (cpp) [Seleccionar]
titular_ = user.nombre() + " " + user.apellidos();

Este campo autocalculado no tiene demasiado sentido... nombre() y apellidos() no son llamadas a operaciones costosas, es mejor autocalcular el valor cuando sea necesario, como los puntos anteriores, no es un fallo, solo una cuestión de diseño.

6. Las clases se crean sólo si hay razón para ello

Código (cpp) [Seleccionar]
class Id_duplicado {
  public:
    Id_duplicado (const Cadena& id) : id_duplicado(id) {}
    const Cadena idd() { return id_duplicado; }
  private:
    const Cadena id_duplicado;
  };


Vista así, esta clase no aporta nada, parece totalmente prescindible. Bien es cierto que lo ideal es tener el código bien repartido en muchas clases, cada una con una única responsabilidad, y con el menor código posible... pero claro, estas clases tienen que tener una razón de ser y esta, vista así, no lo tiene. Llenar el código de clases inútiles te va a dificultar el mantenimiento de tu código y te va a dar problemas en el futuro... estás avisado.

DvNe

A ver ya encontré solución a mi problema pondré todos los ficheros de mi problema ya que hace falta conocer todas las clases para ver el por qué de algunas cosas que apuntas eferion.

CLASE USUARIO JUNTO CON SU IMPLEMENTACION

Código (cpp) [Seleccionar]
#ifndef _USUARIO_H_
#define _USUARIO_H_

#include "articulo.h"
#include "tarjeta.h"

#include <istream>
#include <map>
#include <set>
using std::map;
using std::set;

class Tarjeta;

#include "cadena.h"

class Clave {
public:
  enum Razon {CORTA, ERROR_CRYPT};
 
  class Incorrecta {
  public:
    Incorrecta (const Razon& r) : razon_(r) {}
    Razon razon() const { return razon_; }
  private:
    Razon razon_;
  };
  Clave (const char*) throw (Clave::Incorrecta);

  Cadena clave() const { return pass_cifrada; }
  bool verifica (const char*);
private:
  Cadena pass_cifrada;
};

class Usuario {
public:
  //CONSTRUCTOR Y DESTRUCTOR
  Usuario (const Cadena&, const Cadena&, const Cadena&, const Cadena&, const Clave&);
  ~Usuario();
 
  class Id_duplicado {
  public:
    Id_duplicado (const Cadena& id) : id_duplicado(id) {}
    const Cadena idd() const { return id_duplicado; }
  private:
    const Cadena id_duplicado;
  };
  //FUNCIONES OBSERVADORAS
  Cadena id() const { return identificador_; }
  Cadena nombre() const { return nombre_; }
  Cadena apellidos() const { return apellidos_; }
  Cadena direccion() const { return direccion_; }


  //FUNCIONES CON TARJETAS
  typedef map<Numero, Tarjeta*> Tarjetas;
  void es_titular_de(Tarjeta&);
  void no_es_titular_de(Tarjeta&);
  const Tarjetas& tarjetas() const { return tarjetas_; }

 
  //FUNCIONES CON LOS ARTICULOS
  typedef map<Articulo*, unsigned> Articulos;
  void compra(Articulo& articulo, unsigned cant = 1);
  const Articulos& compra() const { return articulos_; }
  size_t n_articulos() const { return articulos_.size(); }

  //SOBRECARGA OPERADOR
  friend std::ostream& operator << (std::ostream&, const Usuario&);
 
private:
  Cadena identificador_;
  Cadena nombre_;
  Cadena apellidos_;
  Cadena direccion_;
  Clave password_;
  Tarjetas tarjetas_;
  Articulos articulos_;

  Cadena password() const { return password_.clave(); }
  static set<Cadena> identificadores;
  bool IdValido() const throw(Usuario::Id_duplicado);
  Usuario (const Usuario&); //Deshabilitamos la copia de un usuario
};

std::ostream& mostrar_carro(std::ostream&, const Usuario&);
#endif


Código (cpp) [Seleccionar]
#include "usuario.h"
#include <iostream>
#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <unistd.h>

using namespace std;

Clave::Clave (const char* pass_no_cifrada) throw (Clave::Incorrecta) {
  if (strlen(pass_no_cifrada) < 5)
    throw(Incorrecta(CORTA));

  srand(time(0));
  const char* const validos = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  const char salto[2] = {validos[rand() % 63], validos[rand() % 63]};
  if (crypt(pass_no_cifrada,salto) == NULL)
    throw(Incorrecta(ERROR_CRYPT));

  pass_cifrada = crypt(pass_no_cifrada,salto);
}

bool Clave::verifica(const char* pass) {
  return (strcmp(pass_cifrada.c_str(), crypt(pass,pass_cifrada.c_str())) == 0);
}

set<Cadena> Usuario::identificadores;

Usuario::Usuario (const Cadena& identificador, const Cadena& nombre, const Cadena& apellidos, const Cadena& direccion, const Clave& pass) : identificador_(identificador), nombre_( nombre), apellidos_(apellidos), direccion_(direccion), password_(pass) {
  IdValido();
}

Usuario::~Usuario() {
  for (Usuario::Tarjetas::iterator i = tarjetas_.begin(); i != tarjetas_.end(); ++i)
    (*(*i).second).anula_titular();
  identificadores.erase(id());
}

bool Usuario::IdValido() const throw(Usuario::Id_duplicado) {
  pair<set<Cadena>::iterator,bool> i;

  i = identificadores.insert(id());
  if (i.second == false) {
    throw(Id_duplicado(id()));
    return false;
  } else {
    return true;
  }
}

ostream& operator << (ostream& output, const Usuario& user) {
  output <<"\n" << user.id() << " [" << user.password() << "] " << user.nombre() << " "
<< user.apellidos() << "\n" << user.direccion() << "\nTarjetas:\n";
  for (Usuario::Tarjetas::const_iterator i = user.tarjetas().begin(); i != user.tarjetas().end(); ++i)
    output << *(*i).second << "\n";
  return output;
}

void Usuario::compra (Articulo& articulo, unsigned cant) {
  if (cant == 0)
    articulos_.erase(&articulo);
  else {
    if (articulos_.find(&articulo) != articulos_.end())
      articulos_.erase(&articulo);
      articulos_.insert(pair<Articulo*,unsigned>(&articulo,cant));
    }
}

ostream& mostrar_carro(ostream& output, const Usuario& user) {

  output << "Carrito de compra de " << user.id() << " [Articulos: "
       << user.n_articulos() << "]\n Cant. Articulo\n================="
       << "=========================================\n";
  for (Usuario::Articulos::const_iterator  p = user.compra().begin(); p != user.compra().end(); p++)
    output << setfill(' ') << setw(4) <<  p->second << setw(4) << *p->first << "\n";
  return output;
}

void Usuario::es_titular_de(Tarjeta& t) {
  tarjetas_.insert(pair<Numero, Tarjeta*>(t.numero(),&t));
}

void Usuario::no_es_titular_de(Tarjeta& t) {
  tarjetas_.erase(t.numero());
}


CLASE TARJETA Y SU IMPLEMENTACION

Código (cpp) [Seleccionar]
#ifndef _TARJETA_H_
#define _TARJETA_H_

#include "cadena.h"
#include "fecha.h"

class Usuario;

class Numero : public Cadena {
public:
  enum Razon {LONGITUD,DIGITOS,NO_VALIDO};

  class Incorrecto {
  public:
    Incorrecto (const Razon& r) { razon_ = r; }
    Razon razon() const { return razon_; }
  private:
    Razon razon_;
  };

  Numero (const Cadena&) throw (Numero::Incorrecto);
  operator const char*() const {return numero_.c_str(); }
 
private:
  Cadena numero_;
  static const unsigned LongitudMinima = 13;
  static const unsigned LongitudMaxima = 19;
  bool numeroValido() const ;
};

bool operator < (const Numero&, const Numero&);

class Tarjeta {
public:
  class Caducada {
  public:
    Caducada (const Fecha& f) : fecha_(f) {}
    Fecha cuando() const { return fecha_; }
  private:
    Fecha fecha_;
  };
  Tarjeta (const Numero&, const Usuario&, const Fecha&) throw (Tarjeta::Caducada);
  ~Tarjeta();

  Numero numero() const { return numero_; }
  Fecha caducidad() const { return caducidad_; }
  Cadena titular_facial() const { return titular_; }
  const Usuario* titular() const { return user_; }
  void anula_titular() { user_ = 0; }

  friend std::ostream& operator << (std::ostream&, const Tarjeta&);
private:
  Numero numero_;
  const Usuario* user_;
  Fecha caducidad_;
  Cadena titular_;


};

bool operator < (const Tarjeta&, const Tarjeta&);
#endif


Código (cpp) [Seleccionar]
#include "tarjeta.h"
#include "usuario.h"
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <iomanip>

using namespace std;

Tarjeta::Tarjeta (const Numero& n, const Usuario& user, const Fecha& f) throw (Tarjeta::Caducada) : numero_(n), user_(&user), caducidad_(f) {
 
  titular_ = user.nombre() + " " +  user.apellidos();
 
  Fecha f_actual;
  if (caducidad_ <  f_actual) {
    throw(Tarjeta::Caducada(caducidad_));return;
  }
  const_cast<Usuario&>(user).es_titular_de(*this);
}

Tarjeta::~Tarjeta() {
  Usuario* u = const_cast<Usuario*>(user_);
  if (u)
    u->no_es_titular_de(*this);
}


std::ostream& operator << (std::ostream& output, const Tarjeta& t) {
  output << "\n  " << (const char*) t.numero() << "\n  " << t.titular_facial()
<< "\n  Caduca: " << setfill('0') << setw(2) << t.caducidad().mes()
<< "/" << setw(2) << (t.caducidad().anno() % 100);
  return output;
}

Numero::Numero (const Cadena& numero) throw (Numero::Incorrecto) {
  unsigned i = 0, j = 0, pos = 0;

  do {
    pos = i;
    while (i < numero.longitud() && numero[i] != ' ') {
      if (isalpha(numero[i]))
throw(Incorrecto(DIGITOS));
      j++; i++;
    }
    numero_ += numero.subcadena(pos,j);
    j = 0;
    while (i < numero.longitud() && numero[i] == ' ') { i++; }
  } while (i < numero.longitud());

  if (numero_.longitud() < LongitudMinima || numero_.longitud() > LongitudMaxima)
    throw(Incorrecto(LONGITUD));
  if (!numeroValido())
    throw(Incorrecto(NO_VALIDO));
}

bool Numero::numeroValido() const { //Algoritmo de Lhun
  int suma = 0;
  bool impar = true;

  for (int i = numero_.longitud() - 1; i >= 0; i--) {
    if (!impar) {
      int tmp = (numero_[i] - '0') << 1; //Multiplicamos por 2 si es impar
      suma += (tmp >= 10) ? tmp - 9 : tmp;
    } else
      suma += (numero_[i] - '0');
    impar = !impar;
  }
  return (suma % 10) ? false : true;
}

bool operator < (const Numero& numero1, const Numero& numero2) {
  return atoll(numero1) < atoll(numero2);
}

bool operator < (const Tarjeta& t1, const Tarjeta& t2) {
  return t1.numero() < t2.numero();
}

std::ostream& operator << (std::ostream& output, const Numero& num) {
  output << (const char*) num;
  return output;
}


CLASE ARTICULO Y SU IMPLEMENTACION

Código (cpp) [Seleccionar]
#ifndef _ARTICULO_H_
#define _ARTICULO_H_

#include "cadena.h"
#include "fecha.h"

class Articulo {
public:
  Articulo (const Cadena&, const Cadena&, const Fecha&, const double&, const unsigned&);

  Cadena referencia() const { return codigo_Referencia; }
  Cadena titulo() const { return titulo_; }
  Fecha f_publi() const { return publicacion_; }
  double precio() const { return precio_; }
  unsigned stock() const { return ejemplares_; }

  double& precio() { return precio_; }
  unsigned& stock() { return ejemplares_; }

  friend std::ostream& operator << (std::ostream&, const Articulo&);
private:
  Cadena codigo_Referencia;
  Cadena titulo_;
  Fecha publicacion_;
  double precio_;
  unsigned ejemplares_;
};#endif


Código (cpp) [Seleccionar]
#include "articulo.h"
#include <iomanip>

using namespace std;

Articulo::Articulo (const Cadena& ref, const Cadena& title, const Fecha& fecha, const double& price, const unsigned& numero) : codigo_Referencia(ref), titulo_(title), publicacion_(fecha), precio_(price), ejemplares_(numero) {}

ostream& operator << (ostream& output, const Articulo& art) {
  output << "[" << art.referencia() << "] \"" << art.titulo() << "\", " << art.f_publi().anno() << ". " << setprecision(2) << setfill('0') << fixed << art.precio()
<< "\xE2\x82\xAC";
  return output;
}


Ahora bien la razón por la que el proyecto tiene esta implementación, es porque es un trabajo para la universidad.