![]() |
Implementierung eines Interfaces
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? |
Re: Implementierung eines Interfaces
Das sind eigentlich Methoden von TObject. Zeig mal ein bischen Code.
|
Re: Implementierung eines Interfaces
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:
Wenn ich in Delphi mit Interfaces arbeite, benutze ich immer das als Basisklasse:
type
TMyInterfacedClass = class(TInterfacedObject, IMyInterface) ... end;
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? |
Re: Implementierung eines Interfaces
Zitat:
|
Re: Implementierung eines Interfaces
['{F7509748-217A-42EB-B6FB-A45C25310F8A}']
Was ist das? Hat das was mit Serialisierung zu tun? Also mein Code ist bisher so:
Delphi-Quellcode:
EDIT: OK, hab jetzt rausgefunden, wie ichs machen kann. Einfach nicht von TObject ableiten sondern von TInterfacedObject. Danke.
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; |
Re: Implementierung eines Interfaces
Zitat:
|
Re: Implementierung eines Interfaces
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:
Die Zuweisung ist korrekt. Beide implementieren IMyInterface, also wirds hier nicht knallen.
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; 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:
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.
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; } } } } Probiere das selbe in Delphi, und bald wird dein Rechner mit der swapperei anfangen^^ Conclusio: Wenn schon GC, dann richtig ;) |
Re: Implementierung eines Interfaces
Zitat:
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; |
Re: Implementierung eines Interfaces
Zitat:
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... :-) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:00 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz