Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > OOP
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 12-02-2007
Flecha Flecha is offline
Miembro
 
Registrado: nov 2006
Posts: 59
Poder: 18
Flecha Va por buen camino
Cita:
Empezado por mamcx
Deriva las clases de TInterfacedObject y todo bien.

La implementacion que has hecho no funciona con interfaces porque anulaste el sistema de liberacion de memoria!

Gracias por el consejo. No conocía la clase TInterfacedObject, y si te soy sincero tampoco sé muy bien para qué son el QueryInterface, _AddRef, y _Release. Además, eso que comentas de anular el sistema de liberación de memoria la verdad es que me asusta un poco.

No obstante, he mirado en la ayuda de Delphi y creo que no me será necesario usar el TInterfacedObject. De todos modos, por si acaso me equivoco en algo, te mostraré con más detalle lo que tengo y si ves algo que creas que esta mal no dudes en corregirme, ¿vale?

Código Delphi [-]
TYPE

   TClaseBase = class
   private
      ...
   protected
      ...
   public
      ...
   end;

   TMiInterface = interface
      procedure Metodo;
      ...
   end;

   TClasePadre = (TClaseBase, TMiInterface)
   private
      function QueryInterface(const IID: TGUID; out Obj): Integer; stdcall;
      function _AddRef: Integer; stdcall;
      function _Release: Integer; stdcall;
      ...
   protected
      procedure Metodo; virtual; abstract;
      ...
   public
      procedure Ejecutar;
   end;

   TClaseHijo = (TClasePadre)
   private
      ...
   protected
      procedure Metodo; override;
      ...
   public   
   end;

function TClasePadre.QueryInterface(const IID: TGUID; out Obj): Integer; stdcall;
begin
  inherited;
end;
 
function TClasePadre._AddRef: Integer; stdcall;
begin
  inherited;
end;
 
function TClasePadre._Release: Integer; stdcall;
begin
  inherited;
end;
 
procedure TClasePadre.Ejecutar;
begin
  ...
  Metodo;
  ...
end;

Muy resumidamente, es eso lo que yo tengo hecho. En la ayuda de Delphi he visto que TInterfacedObject está declarada de la siguiente manera:

Código Delphi [-]
type
 TInterfacedObject = class(TObject, IUnknown)
 private
   FRefCount: Integer;
 protected
   function QueryInterface(const IID: TGUID; out Obj): Integer; stdcall;
   function _AddRef: Integer; stdcall;
   function _Release: Integer; stdcall;
 public
   property RefCount: Integer read FRefCount;
 end;

Mi clase TClasePadre desciende de TClaseBase (la cual por definición desciende de TObject), y del interface TMiInterface (que desciende de IUnknown). Por tanto entiendo que TClasePadre termina heredando todo lo que necesita de TInterfacedObject, excepto el RefCount.

¿Qué opinas? ¿Necesitaré el RefCount para algo? Cuando compilo, Delphi no me pide que incluya el RefCount dentro de TClasePadre. Y cuando ejecuto, no me aparece ningún mensaje de error ni al crear ni al destruir las clases. ¿Necesitaré incluir RefCount de todos modos? ¿Necesitaré poner algo dentro de los métodos QueryInterface, _AddRef, y _Release aparte del inherited?

Por si te vale de ayuda, estamos hablando de Delphi 3. Muy arcaico, ya lo sé. Pero por desgracia yo no decido mis herramientas de trabajo.

Muchas gracias de nuevo.
Responder Con Cita
  #2  
Antiguo 12-02-2007
Avatar de mamcx
mamcx mamcx is online now
Moderador
 
Registrado: sep 2004
Ubicación: Medellín - Colombia
Posts: 3.912
Poder: 25
mamcx Tiene un aura espectacularmamcx Tiene un aura espectacularmamcx Tiene un aura espectacular
Puedes usar TInterfaceObject de forma segura, de hecho para ello existe.

_AddRef, _Release y RefCount permiten un "recolector de basura" que funciona mediante el conteo de referencias.

La idea es que cada vez se toca un objeto que lo implementa se "aumenta" la cantidad de referencias y luego cuando se suelta el objeto se "decrementa". Cuando el # de referencias llegue a 0, automaticamente se libera el objeto (esto significa que en la practica no es necesario llamar a .Free).

Lo que pasa es que como sabes Delphi (excepto la version .NET) no es un lenguague con GC incorporado y si no se tiene en cuenta las reglas que hay que seguir termina haciendo uno unas vainas muy mal hechas (ej: No se deben mezclar llamadas a interfaces con las de objetos).

TInterfacedObjet es una clase que por decirlo asi, permite a las clases "normales" (que no manejan recolector de basura por referencia) beneficiarse de las ventajas de las interfaces.

Otra nota, es convencion (aunque no obligatoria) llamar las interfaces asi:

IUno
IDos

Y las clases

TUno
TDos
__________________
El malabarista.
Responder Con Cita
  #3  
Antiguo 14-02-2007
Flecha Flecha is offline
Miembro
 
Registrado: nov 2006
Posts: 59
Poder: 18
Flecha Va por buen camino
Question ¿No hay que hacer uso del "Free"?

Gracias por la información.
Pero no entiendo eso de que no sería necesario llamar a Free para liberar la memoria usada por el objeto.

Si tengo la clase siguiente

Código Delphi [-]
TMiClase = class (TInterfaceObject, IMiInterface) ... 
end;


Cuando quiera crearme una instancia de TMiClase tendré que ejecutar algo así

Código Delphi [-]
var MiObjeto : TMiClase;
begin
...
MiObjeto := TMiClase.Create;
...
end;


Y se supone que cuando ya no necesite más MiObjeto y quiera liberar su memoria tendré que hacer uso de esto otro

Código Delphi [-]
MiObjeto.Free;
o
Código Delphi [-]
MiObjeto.Destroy; // aunque siempre se aconseja más el uso de Free
¿Qué has querido decir exactamente al decir que no necesitaría hacer uso del Free?
Responder Con Cita
  #4  
Antiguo 14-02-2007
Avatar de mamcx
mamcx mamcx is online now
Moderador
 
Registrado: sep 2004
Ubicación: Medellín - Colombia
Posts: 3.912
Poder: 25
mamcx Tiene un aura espectacularmamcx Tiene un aura espectacularmamcx Tiene un aura espectacular
Cuando una clase esta bajo el "amparo" de las interfaces tienen su manejo automatico de memoria.

Sin embargo, el manejo se vuelve algo enrevesado si no se conocen las reglas de como funciona, asi que mejor sigue dandole free
__________________
El malabarista.
Responder Con Cita
  #5  
Antiguo 14-02-2007
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
No, no. Si no quieres ver "Invalid pointer operation" y similares, nunca liberes un objeto referenciado por una interfaz que descienda de TInterfacedObject.

Vamos a ver: no es que Delphi maneje automáticamente la memoria de las interfaces. Lo que sucede es que cada vez que se hace referencia a una interfaz, el compilador añade una llamada a _AddRef, y cada vez que una referencia sale de alcance (por ejemplo, si se tiene una variable interfaz en un procedimiento y se sale de éste), el compilador añade una llamada a _Release.

Pero lo que hagan _AddRef y _Release depende de la clase que haya implementado la interfaz. TInterfacedObject es quien implementa la recolección automática al mantener un conteo de cuántas referencias hay. Cuando _Release ve que la cuenta llega a cero, automáticamente llama al destructor del objeto. Por ello, si hacemos nosotros mismos el Free, _Release marcará el "Invalid Pointer Operation", pues intentará hacer un Free de un objeto que ya no existe.

Si implementamos interfaces con clases que desciendan de TInterfacedObject, entonces jamás deben mezclarse referencias a un objeto con referencias a la interfaz. De hecho, la idea de las interfaces es nunca manipular directamente el objeto, sino sólo a través de la interfaz.

// Saludos
Responder Con Cita
  #6  
Antiguo 14-02-2007
Avatar de mamcx
mamcx mamcx is online now
Moderador
 
Registrado: sep 2004
Ubicación: Medellín - Colombia
Posts: 3.912
Poder: 25
mamcx Tiene un aura espectacularmamcx Tiene un aura espectacularmamcx Tiene un aura espectacular
Tienes toda la razon Roman...

Estaba mezclando las cosas en la cabeza....
__________________
El malabarista.
Responder Con Cita
  #7  
Antiguo 15-02-2007
Flecha Flecha is offline
Miembro
 
Registrado: nov 2006
Posts: 59
Poder: 18
Flecha Va por buen camino
Thumbs up

Muchisimas gracias de nuevo.
Ahora sí que me ha quedado todo claro.

Ahora entiendo el mensaje de error que había empezado a aparecerme cuando se cerraba la aplicación y que no era capaz de localizar. Era porque yo ejecutaba la llamada a Free cuando yo ya no necesitaba el objeto, y luego al cerrarse el programa, éste intentaba volver a ejecutar esos mismos Free gestionados por el _Release.

No obstante, me gusta ser yo quien tenga el control y no fiarme de lo que automáticamente vaya a hacer el programa. Prefiero ser yo quien llame a Create y a Free en vez de esperar a que lo haga el propio programa. Además, este código fuente puede variar en los proximos meses y, llegado ese momento, tanto yo como cualquiera de mis compañeros de trabajo tendríamos que acordarnos de este detalle del Free "automático" para este caso tan partícular. Demasiado riesgo fiarse de la memoria humana.
Así que, aunque sólo sea por esta vez, no voy utilizar el TInterfacedObject ya que voy a ser yo quien llame al Free, y la liberación de memoria va a quedar garantizada.

De nuevo muchísimas gracias. Me habéis ayudado muchísimo. Sois unos cracks.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Ventana MDI, "Siempre visible" y "Pantalla completa" ixMike API de Windows 7 11-04-2007 18:36:55
¿cuál es mejor: "close" o "application.terminate"? unreal4u Varios 5 05-03-2007 11:01:19
"ChequeaEsto" elegido el futuro "Killer CLubDelphi" mamcx Noticias 51 31-10-2006 20:56:32
Firebir y usar "IF" en la clausula "SELECT" papulo SQL 6 25-07-2006 21:38:04
porque no me reconoce los caracteres "*" ni "%" cuando filtro mrmago Conexión con bases de datos 10 27-01-2006 04:21:16


La franja horaria es GMT +2. Ahora son las 00:58: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
Copyright 1996-2007 Club Delphi