How can free Interface implemented class?

2019-02-28 15:38发布

问题:

I have a little problem. As the title says I want to release an object whose class implements an interface, however I get an error "invalid pointer operation".

My Interface:

Interface

Type
  // An interface definition
  IMessageEvents = Interface(IInterface)
    ['{BD27EFC6-CC9A-437A-A8B8-16F722518836}']

    Procedure messageReceived(messageData: String);
  End;

Implementation

My Class:

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;

My Code:

 self.chatMng := TChatManager.Create;
 self.chatMng.Free;

Can anyone tell me what I'm doing wrong? Thanks in advance.

回答1:

It would appear that chatMng is of type TChatManager. That can be deduced by the fact that you assign TChatManager.Create to it, and call Free on it.

However, TChatManager derives from TInterfacedObject. That means that its lifetime is controlled by the references that are taken to its interfaces. When the final reference is released, the object is destroyed.

The rule of thumb is that if you derive from TInterfacedObject then you must never take a reference to the object other than through an interface variable.

Steps to correct your code:

  1. Change chatMng to be of type IMessageEvents.
  2. Remove the call to chatMng.Free which the compiler will object to in any case.


回答2:

He must not be showing us all the code...because what he shows should not cause a GPF...you can create a TInterfacedObject and free it...if you don't get a reference to it...but If you get a Reference you are no longer in charge of freeing it...

Here's the Interface

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.

Here's the form

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.

Here's the 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