![]() |
Delphi-Version: XE7
Supports(..) liefert Referenz welche AV auslöst
Ich möchte kein konkretes Problem lösen. Ich möchte nur verstehen warum folgender Code mit der Zeile
Delphi-Quellcode:
eine
if castSuccessful then myIntf.doSomething();
Zitat:
Delphi-Quellcode:
program Project3;
{$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; type IMyInterface = interface ['{88DDD9A5-F4BC-47B9-9240-31B1C986F230}'] procedure doSomething(); end; TMyClass = class(TInterfacedObject, IMyInterface) public constructor Create(); procedure doSomething(); end; procedure justSupportsThings(); var myObject: TObject; myIntf: IMyInterface; castSuccessful: Boolean; begin myObject := TMyClass.Create(); castSuccessful := Supports(myObject, IInterface, myIntf); if castSuccessful then myIntf.doSomething(); end; constructor TMyClass.Create(); begin _AddRef(); // Damit mich das Supports(..) nicht abräumt end; procedure TMyClass.doSomething; begin // nop end; begin try justSupportsThings(); except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; readln; end. Mir ist klar, dass im Aurfuf
Delphi-Quellcode:
die letzten beiden Parameter nicht wirklich zusammenpassen, denn
Supports(myObject, IInterface, myIntf);
Delphi-Quellcode:
ist vom Typ
myIntf
Delphi-Quellcode:
.
IMyInterface = Interface(IInterface)
Bedeutet das etwa dass
Delphi-Quellcode:
die Referenz nur soweit "befüllt" wie ich mit der GUID angebe?
Supports(..)
Ich habe mich mit den ganzen Dingen im Hintergrund (VMT, all das) nie beschäftigt... |
AW: Supports(..) liefert Referenz welche AV auslöst
Nur so fürs Protokoll, versuche es mal so
Delphi-Quellcode:
program dp_183554;
{$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; type IMyInterface = interface ['{88DDD9A5-F4BC-47B9-9240-31B1C986F230}'] procedure doSomething( ); end; TMyClass = class( TInterfacedObject, IMyInterface ) public constructor Create( ); procedure doSomething( ); end; procedure justSupportsThings( ); var myObject: TObject; myIntf: IMyInterface; castSuccessful: Boolean; begin myObject := TMyClass.Create( ); castSuccessful := Supports( myObject, IMyInterface, myIntf ); if castSuccessful then myIntf.doSomething( ); end; constructor TMyClass.Create( ); begin inherited; // Schwachfug // _AddRef(); // Damit mich das Supports(..) nicht abräumt end; procedure TMyClass.doSomething; begin // nop end; begin try justSupportsThings( ); except on E: Exception do Writeln( E.ClassName, ': ', E.Message ); end; readln; end. |
AW: Supports(..) liefert Referenz welche AV auslöst
Natürlich, der Leitsatz aus deiner Signatur greift einfach immer. 8-)
Aber das war mir klar, meine Frage ist ja auch eine andere |
AW: Supports(..) liefert Referenz welche AV auslöst
Supports liefert dir im dritten Parameter einen Zeiger auf die VMT genau des Interfaces, das du abfragst. Da in diesem Fall die Typsicherheit nicht greift, da der Parameter typlos ist, musst du selbst dafür sorgen, daß die Interface-Variable dort auch den passenden Typ hat (nämlich den, den du abfragst).
|
AW: Supports(..) liefert Referenz welche AV auslöst
Ihr müsst ja auch nicht gleich alle auf mir rumhacken :mrgreen:
Dann versuch mal das hier
Delphi-Quellcode:
type
IMyInterface = interface ['{88DDD9A5-F4BC-47B9-9240-31B1C986F230}'] procedure doSomething( ); end; TMyClass = class( TInterfacedObject, IInterface, IMyInterface ) // <- Augen auf public constructor Create( ); procedure doSomething( ); end; procedure justSupportsThings( ); var myObject: TObject; myIntf: IMyInterface; castSuccessful: Boolean; begin myObject := TMyClass.Create( ); castSuccessful := Supports( myObject, IInterface, myIntf ); if castSuccessful then myIntf.doSomething( ); // <- beim Eierkauf - Keine Exception mehr :o) end; |
AW: Supports(..) liefert Referenz welche AV auslöst
Hach ja, das alte Problem, dass "vererbte" Interfaces nicht implizit in der Klasse landen...
|
AW: Supports(..) liefert Referenz welche AV auslöst
Hier mal das Originalbeispiel etwas erweitert. Man vergleiche die Reihenfolge der Methodenaufrufe im Source mit der der tatsächlich ausgeführten Methoden.
Delphi-Quellcode:
program Project4;
{$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.Classes; type IMyInterface = interface ['{88DDD9A5-F4BC-47B9-9240-31B1C986F230}'] procedure doSomething(); end; IMyInterface2 = interface ['{D9B8FC6D-2F71-4E31-A5E7-0CCA98146E78}'] procedure doSomeotherthing(); end; TMyClass = class(TInterfacedPersistent, IMyInterface, IMyInterface2) public procedure doSomething(); procedure doSomeotherthing(); end; procedure justSupportsThings(); var myObject: TObject; myIntf: IMyInterface; myIntf2: IMyInterface2; begin myObject := TMyClass.Create(); try if Supports(myObject, IMyInterface, myIntf) then myIntf.doSomething(); if Supports(myObject, IMyInterface2, myIntf2) then myIntf2.doSomeotherthing(); if Supports(myObject, IMyInterface2, myIntf) then myIntf.doSomething(); if Supports(myObject, IMyInterface, myIntf2) then myIntf2.doSomeotherthing(); finally myObject.Free; end; end; procedure TMyClass.doSomeotherthing; begin Writeln('Someotherthing'); end; procedure TMyClass.doSomething; begin Writeln('Something'); end; begin try justSupportsThings(); except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; readln; end. |
AW: Supports(..) liefert Referenz welche AV auslöst
Zitat:
Entweder man benutzt nur Interface-Referenzen oder nur Objekt-Referenzen. Nur z.B. bei TComponent-Nachfahren kann man Beides benutzen, da dort die Referenzzählung deaktiviert wurde. |
AW: Supports(..) liefert Referenz welche AV auslöst
@himitsu
![]() Und man kann sich auch eine eigene Interfaced-Klasse bauen, die keine Referenzzählung hat. |
AW: Supports(..) liefert Referenz welche AV auslöst
Zitat:
Delphi-Quellcode:
Das Memory Leak ergibt sich nur bei TComponent als Basisklasse. Mit TInterfacedObject als Basisklasse wird das über Interface verwaltete Feld FInt beim Destroy mit freigegeben, und kein Leak bleibt zurück.
program LeakTest;
uses Classes; type MyInterface = interface end; TMyImplementation = class(TComponent, MyInterface) end; TMyContainer = class(TObject) private FInt: MyInterface; public property Impl: MyInterface read FInt write FInt; end; var C: TMyContainer; begin ReportMemoryLeaksOnShutdown := True; C := TMyContainer.Create; C.Impl := TMyImplementation.Create(nil); C.Free; end. Unter Stackoverflow kann man den Hintergrund dieses Verhaltens detailliert nachlesen. ![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:40 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-2025 by Thomas Breitkreuz