Delphi 自由接口如何实现类?
我有个小问题。正如标题所说,我想释放一个对象,该对象的类实现了一个接口,但是我得到了一个错误“无效指针操作” 我的界面:Delphi 自由接口如何实现类?,delphi,class,object,interface,free,Delphi,Class,Object,Interface,Free,我有个小问题。正如标题所说,我想释放一个对象,该对象的类实现了一个接口,但是我得到了一个错误“无效指针操作” 我的界面: Interface Type // An interface definition IMessageEvents = Interface(IInterface) ['{BD27EFC6-CC9A-437A-A8B8-16F722518836}'] Procedure messageReceived(messageData: String); E
Interface
Type
// An interface definition
IMessageEvents = Interface(IInterface)
['{BD27EFC6-CC9A-437A-A8B8-16F722518836}']
Procedure messageReceived(messageData: String);
End;
Implementation
我的班级:
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;
我的代码:
self.chatMng := TChatManager.Create;
self.chatMng.Free;
谁能告诉我我做错了什么?提前感谢。看来
chatMng
属于TChatManager
类型。这可以通过您为其分配TChatManager.Create
并调用Free
来推断
但是,TChatManager
源自TInterfacedObject
。这意味着它的生命周期由对其接口的引用控制。释放最终引用时,对象将被销毁
经验法则是,如果从TInterfacedObject
派生,则除了通过接口变量之外,决不能引用对象
更正代码的步骤:
chatMng
更改为IMessageEvents
类型chatMng.Free
的调用,编译器在任何情况下都会反对该调用他不能向我们展示所有的代码…因为他展示的内容不应该导致GPF…你可以创建一个TInterfacedObject并释放它…如果你没有得到它的引用…但是如果你得到一个引用,你就不再负责释放它 这是界面
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.
这是表格
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.
这是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
您需要显示一些使用显示问题的界面的代码。从你目前所展示的情况来看,没有什么问题,但粗略地猜测,这可能是一个双重自由问题。@afrazier我没有做任何特别的事情。我只是实例化对象,然后尝试释放它。显然,这是一个双重自由问题,但不再尝试释放对象。什么类型的变量是
chatMng
<代码>TChatManager或IMessageEvents
?如果分配了Self
的析构函数或OnDestroy
尝试释放chatMng
“Self.chatMng”是TChatManager类型。我还试着检查对象是否被赋值,我的意思是,如果与NIL不同。事实上,我得到的结果与Nil不同,但在尝试解锁时,我跳过了这个错误。而且,释放chatMng
不会将其设置为Nil
。调用chatMng.Free
后,检查Assigned(chatMng)
仍将返回True
。如果要重新使用chatMng
,则需要确保在调用.Free
后将其设置为nil
。感谢您的响应,但如何明确销毁对象?释放对对象的最终引用时,对象将被销毁。因此,chatMng:=nil
如果没有其他东西包含引用,那么就可以实现这一点。一般来说,您不会显式销毁引用计数对象。我认为接口引用计数只在处理接口变量时发生?这就是说,如果OP将对象传递给请求接口的某个对象,它将在该对象中增加refcount并将其减回到零,然后释放该对象。我怀疑他得到了gpf,因为chatMng是IMessageEvents类型的。。。如果你要放入一个引用…那么你不会释放它…如果你将它放入一个对象…那么如果你没有从中获得引用,你就会释放它…@House No.调用free时会出现编译错误。对Q的评论清楚地证实了我的假设。显然没有人只写:self.chatMng:=TChatManager.Create;自由自在;在两者之间,采用接口引用。同样,你看不到EInvalidPointer并不意味着其他人看不到。取决于内存管理器和运气。@David如果他们只是创建一个概念证明,他们就会这样做……就像我的代码一样……它还没有准备好生产……但它确实证明了事情是如何工作的……我同意你的看法。显然,并不是所有的代码都显示出来了。省略的是获取引用的create和free之间的部分。