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之间的部分。