AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Implementierung eines Interfaces

Ein Thema von 3_of_8 · begonnen am 18. Jun 2006 · letzter Beitrag vom 18. Jun 2006
Antwort Antwort
Benutzerbild von 3_of_8
3_of_8

Registriert seit: 22. Mär 2005
Ort: Dingolfing
4.129 Beiträge
 
Turbo Delphi für Win32
 
#1

Implementierung eines Interfaces

  Alt 18. Jun 2006, 15:55
Morgen.

Ich hab mir grad ein Interface definiert und das dann implementiert.

Der Compiler verlangt nun von mir, dass ich auch die Methoden QueryInterface, _AddRef und _Release implementiere.

Was sind das für Methoden, wie soll ich die implementieren?
Manuel Eberl
„The trouble with having an open mind, of course, is that people will insist on coming along and trying to put things in it.“
- Terry Pratchett
  Mit Zitat antworten Zitat
mkinzler
(Moderator)

Registriert seit: 9. Dez 2005
Ort: Heilbronn
39.858 Beiträge
 
Delphi 11 Alexandria
 
#2

Re: Implementierung eines Interfaces

  Alt 18. Jun 2006, 16:00
Das sind eigentlich Methoden von TObject. Zeig mal ein bischen Code.
Markus Kinzler
  Mit Zitat antworten Zitat
Dax
(Gast)

n/a Beiträge
 
#3

Re: Implementierung eines Interfaces

  Alt 18. Jun 2006, 16:02
QueryInterface benutzt der Compiler bei as-Casts zu Interfaces um zu kucken, ob der zu castende Typ überhaupt dieses Interface implementiert. _AddRef und _Release sind zur Referenzzählung da, wenn die Referenzen auf das Interface auf 0 fallen, gibt es sich automatisch frei: GC für faule -> ausschalten wenn möglich.

Ganz einfach gehts so:
Delphi-Quellcode:
type
  TMyInterfacedClass = class(TInterfacedObject, IMyInterface)
    ...
  end;
Wenn ich in Delphi mit Interfaces arbeite, benutze ich immer das als Basisklasse:
Delphi-Quellcode:
type
  IHAMInterface = interface
    ['{F7509748-217A-42EB-B6FB-A45C25310F8A}']
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;

    procedure AllowDestruction;
  end;

  THAMObject = class(TObject, IHAMInterface)
  private
    fDestroying: Boolean;
  protected
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; virtual; stdcall;
    function _Release: Integer; virtual; stdcall;

    procedure AllowDestruction;
  public
    constructor Create; virtual;

    property Destroying: Boolean read fDestroying write fDestroying;
  end;

procedure THAMObject.AllowDestruction;
begin
  fDestroying := True;
end;

constructor THAMObject.Create;
begin
  inherited;
end;

function THAMObject.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  if GetInterface(IID, Obj) then
    Result := 0
  else
    Result := E_NOINTERFACE;
end;

function THAMObject._AddRef: Integer;
begin
  Result := 1;
end;

function THAMObject._Release: Integer;
begin
  Result := 1;
  if fDestroying then
    Free;
end;

@mkinzler: Eigentlich sinds doch Methoden von TInterfacedObject?
  Mit Zitat antworten Zitat
mkinzler
(Moderator)

Registriert seit: 9. Dez 2005
Ort: Heilbronn
39.858 Beiträge
 
Delphi 11 Alexandria
 
#4

Re: Implementierung eines Interfaces

  Alt 18. Jun 2006, 16:04
Zitat:
@mkinzler: Eigentlich sinds doch Methoden von TInterfacedObject?
Stimmt!
Markus Kinzler
  Mit Zitat antworten Zitat
Benutzerbild von 3_of_8
3_of_8

Registriert seit: 22. Mär 2005
Ort: Dingolfing
4.129 Beiträge
 
Turbo Delphi für Win32
 
#5

Re: Implementierung eines Interfaces

  Alt 18. Jun 2006, 16:33
['{F7509748-217A-42EB-B6FB-A45C25310F8A}']

Was ist das? Hat das was mit Serialisierung zu tun? Also mein Code ist bisher so:

Delphi-Quellcode:
type
  IMap=interface
    function Get(Key: Variant): TObject;
    procedure Put(Key: Variant; Data: TObject);
    procedure Insert(Key: Variant; Data: TObject);
    procedure Delete(Key: Variant);
    property Data[Key: Variant]: TObject read Get write Put; default;
  end;

  TTreeMap = class(TObject, IMap)
  protected
    FRoot: TTreeMapNode;
  public
    function Get(Key: Variant): TObject;
    procedure Put(Key: Variant; Data: TObject);
    procedure Insert(Key: Variant; Data: TObject);
    procedure Delete(Key: Variant);
    property Data[Key: Variant]: TObject read Get write Put; default;
  end;
EDIT: OK, hab jetzt rausgefunden, wie ichs machen kann. Einfach nicht von TObject ableiten sondern von TInterfacedObject. Danke.
Manuel Eberl
„The trouble with having an open mind, of course, is that people will insist on coming along and trying to put things in it.“
- Terry Pratchett
  Mit Zitat antworten Zitat
Basilikum

Registriert seit: 9. Aug 2003
389 Beiträge
 
Delphi 7 Professional
 
#6

Re: Implementierung eines Interfaces

  Alt 18. Jun 2006, 16:58
Zitat von Dax:
gibt es sich automatisch frei: GC für faule -> ausschalten wenn möglich.
kannst du zu dieser Aussage eine Erklärung/Begründung geben ?
  Mit Zitat antworten Zitat
Dax
(Gast)

n/a Beiträge
 
#7

Re: Implementierung eines Interfaces

  Alt 18. Jun 2006, 17:17
Kann ich:

Referenzzählung bei Interfaces ist ähnlich wie die von Strings. Pro Interface-Variable, der eine Instanz der implementierenden Klasse zugewiesen wird, wird der Referenzzähler dieser Klasseninstanz um 1 erhöht. Rennt die Variable aus dem Scope, wird der Zähler entsprechend um 1 verringert. Sobald der Zähler auf 0 fällt, gibt sich die Klasse automatisch frei - kein Speicherleck entsteht, wenn der ursprüngliche Zeiger auf die Klasseninstanz verloren ist. So weit, so gut.

Aber was passiert hier?
Delphi-Quellcode:
IMyInterface = interface
    function GetPartner: IMyInterface;
  end;

TMyClass = class(TInterfacedObject, IMyInterface)
private
  fPartner: IMyInterface;
  procedure SetPartner(const Value: IMyInterface);
  function GetPartner: IMyInterface;
public
  property Partner: IMyInterface read GetPartner write SetPartner;

...

var
  His, Her: TMyClass;

His := TMyClass.Create();
Her := TMyClass.Create;

His.Partner := Her;
Her.Partner := His;
Die Zuweisung ist korrekt. Beide implementieren IMyInterface, also wirds hier nicht knallen.

Jetzt stell dir vor, His rennt aus dem Scope. His' Referenzzähler dropt auf 1. Bei Her ist es genauso. Wenn beide aus dem Scope rennen, droppen beide Zähler auf 1! Speicherleck! Die Klassen hinter den Interfaces werden nicht mehr freigegeben.

Nimm mal dieses C#-Programm und lass es laufen:
Code:
namespace GCTest
{
   interface IPerson {
      IPerson Partner {get; set;}
   }
   
   class Person : IPerson
   {
      int[] DNA = new int[512];
      
      private IPerson partner;
      public IPerson Partner {
         get { return partner; }
         set { partner = value; }
      };
   }
   
   class MainClass
   {
      public static void Main(string[] args)
      {
         while(true) {
            IPerson he, her;
            he = new Person();
            her = new Person();
            he.Partner = her;
            her.Partner = he;
         }
      }
   }
}
Währenddessen beobachte die Speicherauslastung. Es werden jede Menge Paare erstellt - aber die Speicherauslastung geht (bei mir zumindest) nie über 5MB hinaus. Das ist GarbageCollection. Der GC erkennt automatisch, das keine nutzbare Referenz auf die Instanzen mehr vorhanden ist und killt diese aus dem Speicher. Es gibt zwar noch Referenzen - die partner-Referenzen - aber mit denen kann das Programm nix mehr anfangen.

Probiere das selbe in Delphi, und bald wird dein Rechner mit der swapperei anfangen^^

Conclusio: Wenn schon GC, dann richtig
  Mit Zitat antworten Zitat
Elvis

Registriert seit: 25. Nov 2005
Ort: München
1.909 Beiträge
 
Delphi 2010 Professional
 
#8

Re: Implementierung eines Interfaces

  Alt 18. Jun 2006, 17:22
Zitat von Basilikum:
Zitat von Dax:
gibt es sich automatisch frei: GC für faule -> ausschalten wenn möglich.
kannst du zu dieser Aussage eine Erklärung/Begründung geben ?
Delphi interfaces sind COM interfaces:
Wenn eine Interface-Instanz aus dem Scope rennt oder eine Referenz entfernt wird, veringert sich ihr Referenzzähler.
Erreicht er 0 wird die Instanz zerstört.
Wenn du nicht von TInterfacedObject erbst, kannst du selbst entscheiden, ob du die Referenzen zählen willst. TComponent zum Beispiel hat die Referenzzählung abgeschalten.

Deshalb reicht das hier:
Delphi-Quellcode:
var
  instance : IMyInterface;
begin
  instance := SomeImplementingClass.Create();
  instance.DoSomething();
end;
Robert Giesecke
I’m a great believer in “Occam’s Razor,” the principle which says:
“If you say something complicated, I’ll slit your throat.”
  Mit Zitat antworten Zitat
Basilikum

Registriert seit: 9. Aug 2003
389 Beiträge
 
Delphi 7 Professional
 
#9

Re: Implementierung eines Interfaces

  Alt 18. Jun 2006, 19:44
Zitat von Dax:
Probiere das selbe in Delphi, und bald wird dein Rechner mit der swapperei anfangen^^

Conclusio: Wenn schon GC, dann richtig
dein Beispiel ist so absolut korrekt - aber meines Erachtens etwas an den Haaren herbeigezogen... wenn man so will, wird man bei vielen Konzepten ein Fall finden, bei dem es versagt - insofern finde ich es etwas unpassend, danach sofort das ganze Konzept zu "ächten"...

ich arbeite sehr oft mit Interfaces (Delphi für Win32) und habe bisher noch nie den Fall angetroffen, bei dem Konzept-bedingt Speicherlecks entstehen... aber ich finde Interfaces eine feine Sache (Kapselung, automatische Destruktion, etc.)...

ich entwickle vorwiegend Server-Dienste, die x Wochen lang am Stück laufen - ich denke, etwaige Memory-Leaks hätten sich unterdessen bemerkbar gemacht...
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:37 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz