Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Como puedo asignar una copia de una instancia sin que sea una referencia. (https://www.clubdelphi.com/foros/showthread.php?t=76533)

TecnoBestia 08-11-2011 00:29:56

Como puedo asignar una copia de una instancia sin que sea una referencia.
 
Hola amigos, una vez más requiero de su gran ayuda.

Tengo una clase definida de esta manera:

Código:

Individuo=class(TObject)
  private
  protected
  public
    VClasificacion:VectorIR;
    VCoordenadas:VectorIR;
    Inercia:Double;
    VDistancias:VectorIR;
    TieneClasesVacias:Boolean;
    procedure CargarClasificacionYDistancias();
    procedure GenerarVecino(CantiParticion:Integer);
    procedure CGRealesParaClasificacion();
    function RecalcularInercia:Double;
  published
    //destructor Destroy; override;
end;

Si tengo dos variables Var1 y Var 2 de tipo Individuo, de manera que dependiendo de una condición, no importa cual sea, se debe guardar el contenido de Var1 en Var2 para luego cambiar Var1 o bien destruirlo para luego reutilizarlo. La situación es la siguiente, si ejecuto el siguiente código:

Código:

Var2:=Var1;
Var1.Destroy;

Esto me destruye también a Var2, me suena que lo anterior lo que hace es una asignación de punteros y cuando cambio Var1 luego de guardarlo en Var2, se me cambia lo contenido en Var1.

Mi pregunta es: ¿existe una forma de realizar la asignación de modo que se me guarde una copia y no una referencia al mismo espacio de memoria?

Con el fin de modificar luego una de las variables manteniendose la otra intacta.

Gracias de antemano por su valiosa ayuda.

escafandra 08-11-2011 01:16:25

Escribe un procedimiento Assign que asigne todas las propiedades de tu clase.

TPersistent tiene ese método virtual, así que puedes derivar de TPersistenty completar tu Assign con las nuevas propiedades de tu clase.

Por supuesto puedes realizar tu método de asignación desde cero.

Cuando se realizan asignaciones de este tipo se debe tener cuidado al asignar punteros y en este sentido todos los objetos VCL lo son, así que tendrás que asignar contenidos. Por eso lo mejor es usar el Assign de las clases VCL y completar la asignación de lo propio de nuestra clase.

Saludos.

TecnoBestia 08-11-2011 04:23:15

Muchas gracias. Cambie TObject por TPersistent y coloqué un nuevo procedimiento
Código:

  procedure Individuo.Assign(IndiEnviado:Individuo);
  begin
    VCoordenadas:= IndiEnviado.VCoordenadas;
    VClasificacion:=IndiEnviado.VClasificacion;
    VDistancias:=IndiEnviado.VDistancias;
    Inercia:=IndiEnviado.Inercia;
    TieneClasesVacias:=IndiEnviado.TieneClasesVacias;
  end;

y todo parece funcionar bien.

Gracias por su aporte y su valioso tiempo.

ecfisa 08-11-2011 04:59:16

Hola TecnoBestia.

Me alegra que hayas solucionado el problema, pero creo que el amigo escafandra se refería a algo parecido a esto:
Código Delphi [-]
...
type
  TIndividuo = class(TPersistent)
    procedure Assign(aCustomer: TPersistent); override;
  private
    FNombre: string;
    FEdad: Integer;
    ...
  public
    ...
    property Nombre: string read FNombre write FNombre;
    property Edad  : integer read FEdad write FEdad;
   ...
  end;

procedure TIndividuo.Assign(aCustomer: TPersistent);
begin
  if aCustomer is TIndividuo then
  begin
    FNombre := TIndividuo(aCustomer).FNombre;
    FEdad   := TIndividuo(aCustomer).FEdad;
    ...
  end
  else
    inherited Assign (aCustomer);
end;
...
end.

//--------------------------------------------------------------
...
procedure TForm1.btnAssign(Sender: TObject);
var
  Individuo1, Individuo2: TIndividuo;
begin
  Individuo1 := TIndividuo.Create;
  Individuo1.Nombre := 'PEPE';
  Individuo1.Edad := 15;
  Individuo2 := TIndividuo.Create;
  Individuo2.Assign(Individuo1);
  Individuo1.Free;
  ShowMessage(Format('%s %d',[Individuo2.Nombre, Individuo2.Edad]));
  ...
end;

Un saludo.

escafandra 08-11-2011 15:09:32

Exacto, se trata de sobreescribir el método Assign para añadir en él las asignaciones de las propiedades propias de nuestra nueva clase, tal como muestra ecfisa en su código.

TecnoBestia, se trata de sobrecargar la función virtual para terminar llamando a la heredada, en otro caso te pierdes las propiedades de la clase madre.

Saludos.

Delphius 08-11-2011 16:16:22

¿Y Vale la pena heredar desde TComponent sólo por un método? Antes a cambios en la estructura jerárquicas de nuestras clases es mejor pensarlo dos veces.

¿Te aporta alguna otra ventaja que sea de la clase TComponent? ¿necesitarás hacer streaming para recuperar datos?

¿En que te afecta, o que tan complicado es directamente añadirle un método CopiarA() que haga un trabajo similar? Digo... siendo honestos es lo mismo que harías con el Assing:

Código Delphi [-]
ObjDestino.Propiedad := ObjFuente.Propiedad;

Con todo repeto, me parece un desperdicio heredar de TComponent si en verdad la clase no se va a comportar como un componente.

Saludos,

Al González 08-11-2011 16:34:50

Muy puntual lo dicho por ecfisa y escafandra. :)

Solamente una observación:
Cita:

Empezado por escafandra (Mensaje 417898)
[...] se trata de sobrecargar la función virtual para terminar llamando a la heredada [...]

Tratándose de la palabra reservada Override, el término es redefinir (en el ejemplo se redefine un método virtual), mientras que el término sobrecarga tiene que ver con el uso de Overload, lo cual es otro concepto. Seguro que escafandra así lo entiende también y fue simplemente un despiste. :)

Saludos.

Al González.

maeyanes 08-11-2011 16:40:05

Hola...

Delphius, según creo recordar, TComponent desciende de TPersistent y no al revés. A lo que voy es que heredar una clase de TPersistent no hace que esta se comporte como un componente. TPersistent solo define métodos para serializar un objeto.


Saludos...

TecnoBestia 08-11-2011 16:42:24

Más sobre mi problema
 
Mi clase es muy simple y es para la aplicación de un algoritmo denominado Simulating Annealing para hacer clasificación de datos, mi clase es un Individuo que que contendrá únicamente lo que se muestra en el código siguiente:
Código PHP:

Individuo=class(TObject)
  private
  protected
  public
    
VClasificacion:VectorIR;
    
VCoordenadas:VectorIR;
    
Inercia:Double;
    
VDistancias:VectorIR;
    
TieneClasesVacias:Boolean;
    
procedure CargarClasificacionYDistancias();
    
procedure GenerarVecino(CantiParticion:Integer);
    
procedure CGRealesParaClasificacion();
    function 
RecalcularInercia:Double;
  
published
    
//destructor Destroy; override;
end

Si creo la clase derivada de TObject y genero el procedimiento GenerarCopia tal como se muestra en el código siguiente


Código PHP:

  procedure Individuo.GenerarCopia(IndiEnviado:Individuo);
  
begin
    VCoordenadas
:= IndiEnviado.VCoordenadas;
    
VClasificacion:=IndiEnviado.VClasificacion;
    
VDistancias:=IndiEnviado.VDistancias;
    
Inercia:=IndiEnviado.Inercia;
    
TieneClasesVacias:=IndiEnviado.TieneClasesVacias;
  
end

Y uso éste para poder realizar la copia y no la asignación del puntero, ¿qué problema tendría? ¿qué estoy perdiento al hacerlo así, ya que en este momento me está funcionando? Pero claro que si es mejor hacerlo de la manera que ustedes indican lo haré sin problema.

roman 08-11-2011 16:55:33

Cita:

Empezado por maeyanes (Mensaje 417910)
Delphius, según creo recordar, TComponent desciende de TPersistent y no al revés. A lo que voy es que heredar una clase de TPersistent no hace que esta se comporte como un componente. TPersistent solo define métodos para serializar un objeto.

Así es. Aún así, aplica lo que comenta Delphius. ¿Vale la pena derivar de TPersistent?

// Saludos

Delphius 08-11-2011 17:45:52

Cita:

Empezado por maeyanes (Mensaje 417910)
Hola...

Delphius, según creo recordar, TComponent desciende de TPersistent y no al revés. A lo que voy es que heredar una clase de TPersistent no hace que esta se comporte como un componente. TPersistent solo define métodos para serializar un objeto.


Saludos...

¡Tienes razón! Siempre me confundo a estas dos clases. :o Tengo que estudiar más y mejor :D

Pero como dijo román, el planteo sigue siendo igual de válido. ¿Vale la pena heredar la clase sólo por un método? Yo no creo.

Saludos,

TecnoBestia 08-11-2011 18:10:18

Hola, ¿De quien me recomiendan heredar?
¿Puedo heredar de TOject y crear un procedimiento Copiar? algó así como
Código PHP:

  procedure Individuo.CopiarInstancia(IndiEnviado:Individuo);
  
begin
    VCoordenadas
:= IndiEnviado.VCoordenadas;
    
VClasificacion:=IndiEnviado.VClasificacion;
    
VDistancias:=IndiEnviado.VDistancias;
    
Inercia:=IndiEnviado.Inercia;
    
TieneClasesVacias:=IndiEnviado.TieneClasesVacias;
  
end

¿pierdo algo al hacerlo así?

Gracias por sus acertadas respuestas :).

maeyanes 08-11-2011 18:12:56

Hola...

Para tu caso en particular, no veo por que no hacerlo así, ya que es una clase simple y no necesitas sobrecargarla con métodos que ni vas a usar.


Saludos...

TecnoBestia 08-11-2011 18:39:19

Gracias, lo haré así.

escafandra 08-11-2011 19:19:06

Y volviendo a la idea de Delphius si la clase es tan simple, ¿porqué definirla como derivada de otra? ¿Que se quiere heredar?


Saludos.

escafandra 08-11-2011 19:58:13

Cita:

Empezado por Al González (Mensaje 417909)
Tratándose de la palabra reservada Override, el término es redefinir (en el ejemplo se redefine un método virtual), mientras que el término sobrecarga tiene que ver con el uso de Overload, lo cual es otro concepto. Seguro que escafandra así lo entiende también y fue simplemente un despiste.

Tienes toda la razón en tu observación Al González, así lo entiendo yo también. :)

Saludos.


La franja horaria es GMT +2. Ahora son las 16:34:43.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi