Einzelnen Beitrag anzeigen

Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#12

Re: Interface referenzen auf gleichheit prüfen?

  Alt 11. Okt 2004, 21:45
Nein, dein Weg funktioniert eben nicht. Der AS Operator ist ein verkapselter Aufruf von A.QueryInterface(var B, GUID: TGUID). D.h. der Code


Delphi-Quellcode:
  A := B as IInterfaceType

ist identisch mit

  if B.QueryInterface(A, IInterfaceType) <> S_OK then raise Exception.Create(...);
So erstmal der erste Schritt, nun der zweite:

Eine Impelentierende Klasse kann nun .QueryInterface() überschreiben und dynamisch auf Anforderung ein neues Implemntierendes Object erzeugen das die geforderte Schnittstelle implementiert, also in etwa so:

Delphi-Quellcode:
function TClassA.QueryInterface(var Unk; const GUID: TGUID): HResult; stdcall;
begin
  Result := S_OK;
  if GUID = IInterfaceType then IInterface(Unk) := TImplementorClass.Create
    else Result := inherited QueryInterface(Unk, GUID);
end;

In diesem Moment erzeugt also die Klasse TClassA ein ganz neues Object das die geforderte Schnittstelle IInterfaceType tatsächlich implementiert. Bei solch einer Implementierung, die sehr oft verwendet wird, kann dein einfacher Vergleich der Variablenpointer nicht mehr funktionieren, denn nun würde ja alles, selbst die Impelemntierende Klasse vollständig von der eigentlichen Klasse gekapselt sein.

Also sowas wie:

Delphi-Quellcode:
var
  A,B,C: IInterface;
begin
  A := TClassA.Create;
  
  B := A as IInterfaceType;
  C := A as IInterfaceType;

  Assert( B <> C );
end;
B ist immer ungleich C da der cast (A as IInterfaceType) -> A.QueryInterface() eben intern bei jeder Abfrage ein eigenes neues Interface erzeugt.


Zitat:
Es bleibt maximovs Einwand, dass diese Information eigentlich schon implizit vorhanden und gegeben ist durch die Identät des Objekts.
Und das stimmt eben nicht. Interfaces besitzen per Konzept keine Identität auf deren Implementierung und somit kann auch eine Delphi VCL Klasse nicht ihre implementierende und eindeutige Klassen-Identität auf deren implementierte Interfaces übertragen. Der Weg den die RT /bzw. der Delphi Compiler die Interfaces im Klassendesign über die RTTI umsetzt ist absolut Delphi typisch und nicht dokumentiert. Andere Compiler können das komplett anders handhaben.

Der Delphi Compiler legt im Codesegement die VMT des Interfaces als Konstante an. Die einzelnen Methoden dieses Interfaces zeigen eber nicht direkt auf die Methoden der implementierenden Klasse sondern auf Dispatcher Methoden die durch den Compiler erzeugt wurden. Für jede Methode im Interface gibt es eine eigene Dispatcher Funktion. Diese Dispatcherfunktion berechnet nun aus dem übergebenen Interface Zeiger per Offset den Self Zeiger des Objectes. Dieser Offset ist für jede Interface implementierende Klasse und für jedes einzelene Interface dieser Klasse selber unterschiedlich.

Nun, auch wenn man dies weis und als Ausgangsbasis für eine Identität zum direkten Vergleich von Interfacezegern heranziehen könnte, so ist diese Art und Weise der Impelemntierung von Interfaces eben Delphi typisch und zudem auch undokumentiert.

Nein, das was ich oben sagte stimmt auch weiterhin. Maximov sollte überlegen ob sein Konzept richtig ist, und ob er nicht zuviel von den Interfaces abverlangt. Mein oben vorgeschlagener Weg ist eine saubere Lösung, und für meine Begriffe die einzigst saubere überhaupt. Denn selbst wenn Delphi die Art und Weise wie es Interfaces mit Klassen/Objecten verbindet ändert, oder sogar wenn man auf diese Weise Interfaces die durch verschiedene Compiler erzeugt wurden, vergleicht, so funktioniert das immer sauber.

Gruß Hagen
  Mit Zitat antworten Zitat