delphi - ¿Cómo puede la interfaz implementada la clase gratuita?
class object (2)
Tengo un pequeño problema. Como el título dice que quiero liberar un objeto cuya clase implemente una interfaz, sin embargo, aparece el error "operación de puntero no válida" .
Mi interfaz:
Interface
Type
// An interface definition
IMessageEvents = Interface(IInterface)
[''{BD27EFC6-CC9A-437A-A8B8-16F722518836}'']
Procedure messageReceived(messageData: String);
End;
Implementation
Mi clase:
Type
TChatManager = Class(TInterfacedObject, IMessageEvents)
Private
Protected
Procedure messageReceived(messageData: String); Overload;
Public
Constructor Create; Overload;
Destructor Destroy; Override;
Procedure connect;
Procedure disconnect;
End;
Implementation
Constructor TChatManager.Create;
Begin
{ ....... }
End;
Procedure TChatManager.connect;
Begin
{ ....... }
End;
Procedure TChatManager.disconnect;
Begin
{ ....... }
End;
Procedure TChatManager.messageReceived(messageData: String);
Begin
{ ....... }
End;
Destructor TChatManager.Destroy;
Begin
Inherited Destroy;
End;
Mi código:
self.chatMng := TChatManager.Create;
self.chatMng.Free;
¿Alguien puede decirme lo que estoy haciendo mal? Gracias por adelantado.
Parece que chatMng
es de tipo TChatManager
. Esto se puede deducir por el hecho de que asigne TChatManager.Create
a él y llame a Free
en él.
Sin embargo, TChatManager
deriva de TInterfacedObject
. Eso significa que su duración está controlada por las referencias que se llevan a sus interfaces. Cuando se lanza la referencia final, el objeto se destruye.
La regla general es que si deriva de TInterfacedObject
, nunca debe tomar una referencia al objeto que no sea a través de una variable de interfaz.
Pasos para corregir tu código:
- Cambie
chatMng
por ser de tipoIMessageEvents
. - Elimine la llamada a
chatMng.Free
que el compilador se opondrá en cualquier caso.
No debe mostrarnos todo el código ... porque lo que muestra no debe causar un GPF ... puedes crear un TInterfacedObject y liberarlo ... si no obtienes una referencia ... pero si obtienes una referencia, ya no estás a cargo de liberarla ...
Aquí está la interfaz
unit Unit3;
Interface
uses
Classes, SysUtils;
Type
// An interface definition
IMessageEvents = Interface(IInterface)
[''{BD27EFC6-CC9A-437A-A8B8-16F722518836}'']
Procedure messageReceived(messageData: String);
End;
Type
TChatManager = Class(TInterfacedObject, IMessageEvents)
Private
FStrings: TStrings;
Protected
Procedure messageReceived(messageData: String); Overload;
procedure UpdateStatus(aString: string);
Public
Constructor Create(aStrings: TStrings);
Destructor Destroy; Override;
Procedure connect;
Procedure disconnect;
End;
Implementation
Constructor TChatManager.Create(aStrings: TStrings);
Begin
{ ....... }
FStrings := aStrings;
UpdateStatus(''Created'');
Connect;
End;
Procedure TChatManager.connect;
Begin
{ ....... }
UpdateStatus(''Connected'');
End;
Procedure TChatManager.disconnect;
Begin
{ ....... }
UpdateStatus(''DisConnected'');
End;
Procedure TChatManager.messageReceived(messageData: String);
Begin
{ ....... }
UpdateStatus(''Message Received'');
UpdateStatus(messageData);
End;
procedure TChatManager.UpdateStatus(aString: string);
begin
FStrings.Add(aString);
FStrings.Add(''RefCount: ''+ IntToStr(Self.RefCount));
end;
Destructor TChatManager.Destroy;
Begin
Disconnect;
UpdateStatus(''Destroyed'');
Inherited Destroy;
End;
end.
Aquí está la forma
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, unit3, StdCtrls;
type
TForm2 = class(TForm)
Button1: TButton;
Memo1: TMemo;
Button2: TButton;
Button3: TButton;
Button4: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
{ Private declarations }
chatMng: TChatManager;
iChatMng: IMessageEvents;
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
type
THackManager= class(TChatManager);
procedure TForm2.Button1Click(Sender: TObject);
begin
chatMng := TChatManager.Create(Memo1.Lines);
THackManager(ChatMng).messageReceived(''Hello World from Button1'');
chatMng.Free;
end;
procedure TForm2.Button2Click(Sender: TObject);
begin
iChatMng := TChatManager.Create(Memo1.Lines);
iChatMng.messageReceived(''Hello World from Button2'');
iChatMng := nil;
end;
procedure TForm2.Button3Click(Sender: TObject);
begin
ChatMng := TChatManager.Create(Memo1.Lines);
(ChatMng as IMessageEvents).messageReceived(''Hello World from Button3'');
//you can''t call ChatMng...it''s gone bye bye...
//ChatMng.Free; //this will cause a GPF if you call free
end;
procedure TForm2.Button4Click(Sender: TObject);
var
a_IChatMng: IMessageEvents;
begin
ChatMng := TChatManager.Create(Memo1.Lines);
a_IChatMng := chatMng;
(ChatMng as IMessageEvents).messageReceived(''Hello World from Button4'');
a_IChatMng.messageReceived(''Hello World again from Button4'');
//ChatMng.Free; //this will cause a GPF if you call free
end;
end.
Aquí está el dfm
object Form2: TForm2
Left = 326
Top = 94
Caption = ''Form2''
ClientHeight = 292
ClientWidth = 581
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = ''Tahoma''
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 40
Top = 200
Width = 75
Height = 25
Caption = ''Button1''
TabOrder = 0
OnClick = Button1Click
end
object Memo1: TMemo
Left = 40
Top = 32
Width = 411
Height = 129
TabOrder = 1
end
object Button2: TButton
Left = 160
Top = 200
Width = 75
Height = 25
Caption = ''Button2''
TabOrder = 2
OnClick = Button2Click
end
object Button3: TButton
Left = 272
Top = 200
Width = 75
Height = 25
Caption = ''Button3''
TabOrder = 3
OnClick = Button3Click
end
object Button4: TButton
Left = 376
Top = 200
Width = 75
Height = 25
Caption = ''Button4''
TabOrder = 4
OnClick = Button4Click
end
end