![]() |
Interfaces und Vererbung?
Hallo Delphianer!
Ich hab mal einwenig mit Interfaces herumgespielt und aus Quellen hier im Forum eine kleine Schnittstellen-DLL zusammengebaut. Leider kriege ich eine Zugriffsverletzung und bin mir nicht im klaren darüber was der Grund dafür ist. Folgender Code befindet sich in der DLL:
Delphi-Quellcode:
Dazu gibts eine kleine Schnittstellen-Unit die ich auch im Hauptprojekt verwende:
library IntfDll;
uses uBasic in 'uBasic.pas'; {$R *.res} Type TBasic = Class(TInterfacedObject, IBasic) private fValue: Integer; public constructor Create; virtual; function Basic: Integer; stdcall; end; TBasic2 = Class(TBasic, IBasic2) private fValue2: Integer; public constructor Create; override; function Basic2: Integer; stdcall; end; function GetIntf(Id: Integer): IBasic; stdcall; begin Case Id Of 0: Result := TBasic.Create; 1: Result := TBasic2.Create; Else Result := NIL; End; end; constructor TBasic.Create; begin inherited; fValue := 1; end; function TBasic.Basic: Integer; begin Result := fValue; end; constructor TBasic2.Create; begin inherited; fValue2 := 2; end; function TBasic2.Basic2: Integer; begin Result := fValue + fValue2; end; exports GetIntf; begin end.
Delphi-Quellcode:
Und zum Abschluss das Testprogramm dazu:
unit uBasic;
interface Type IBasic = Interface ['{BF08333B-DBEE-4108-9466-6ECEE4AFD9A1}'] function Basic: Integer; stdcall; end; IBasic2 = Interface(IBasic) ['{38E3D185-5337-4C5B-A3C8-FC7BBC82B855}'] function Basic2: Integer; stdcall; end; function GetIntf(Id: Integer): IBasic; stdcall; implementation function GetIntf(Id: Integer): IBasic; external 'IntfDll.dll' name 'GetIntf'; end.
Delphi-Quellcode:
program Tester;
{$APPTYPE CONSOLE} uses SysUtils, windows, uBasic in 'uBasic.pas'; Var B: IBasic; B2: IBasic2; begin WriteLn; B := GetIntf(0); // WriteLn('Basic.Basic = ',B.Basic); B := NIL; WriteLn; B2 := IBasic2(GetIntf(1)); WriteLn('Basic2.Basic = ', B2.Basic); WriteLn('Basic2.Basic2 = ', B2.Basic2); //<-crash B2 := NIL; end. Ich will in der Art von TBasic noch weiter Klassen ableiten (mit zugehörigem Interface) aber auch von TBasic2 und GetIntf soll mir dann das Interface liefern... Das ganze sollte im übrigen auch von C# aus ansprechbar sein (muss ich da auf was besonderes achten?)... Ich wäre für jeden Hinweis dankbar, bzw. mach ich ja was grundlegend falsch? /edit: inherited zu TBasic.Create hinzugefügt LG |
Re: Interfaces und Vererbung?
bezüglich C#:
die Aufrufkonventionen (stdcall) und die verwendeten Typen (Integer) sollten da keine Probleme machen. > keine Objekte, dynamische Arrays, Strings (String, AnsiString, UnicodeString) verwenden ... möglichst also nichts delphispezifisches (WideString geht aber, da es intern ein C-Typ ist) ansonsten konnte ich jetzt keinen Fehler entdecken, außer daß in TBasic.Create das inherited fehlt. |
Re: Interfaces und Vererbung?
ersetze mal das
Delphi-Quellcode:
durch
B2 := IBasic2(GetIntf(1));
Delphi-Quellcode:
B2 := GetIntf(1) as IBasic2;
|
Re: Interfaces und Vererbung?
Der hardcast eines interfaces bewirkt ein interface copy und keinen interface cast. Der korrekte Weg wäre:
Delphi-Quellcode:
wenn du sicher bist, dass dein angefordertes Interface IBasic auch IBasic2 unterstützt, ansonsten bist du mit
B2 := GetIntf(1) as IBasic2;
Delphi-Quellcode:
auf der sicheren Seite.
if Supports(GetIntf(1), IBasic2, B2) then
|
Re: Interfaces und Vererbung?
Zitat:
LG |
Re: Interfaces und Vererbung?
Achtung! In Delphi 2009 gibt es zusätzlich den Typen UnicodeString, aber du musst weiterhin WideString verwenden. UnicodeString wird nämlich von Delphi verwaltet, WideString aber von COM. Nur mit WideString kann C# direkt umgehen.
|
Re: Interfaces und Vererbung?
Jupp, der UnicodeString ist quasi die Erweiterung vom AnsiString
- läuft über den Delphi-Speichermanager - verfügt über 'ne Referenzzäählung - ist praktisch auch wie ein dynamisches Array aufgebaut - also vorwiegend delphieigenes Zeugs der WideString ist dagegen eine Kapselung einiger Befehle der oleaut32.dll, welche man also auch in C zur Verfügung hat ![]() ![]() ![]() ![]() |
AW: Interfaces und Vererbung?
Zitat:
Normaler Weise werden die Methoden bei Interfaces über eine Art "einfache Liste mit Methodenzeigern" verwaltet. Und bei der Interface-Vererbung werden einfach vom neuen Interface die Methoden hinten drangehängt. Und genau deswegen kann/darf man nicht einfach Methoden weglassen oder in anderer Reihenvolge deklarieren, wenn man "Kopieen" eines Interfaces erstellt.
Delphi-Quellcode:
type
IMyIntfA = interface procedure Aaa; {0} procedure Bbb; {1} procedure Cee; {2} procedure Ddd; {3} procedure Eee; {4} procedure Fff; {5} procedure Ggg; {6} end; IMyIntfB = interface procedure Aaa; {0} procedure Bbb; {1} procedure Cee; {2} procedure Eee; {3} // vertauscht procedure Ddd; {4} // procedure Fff; {5} // hier fehlt was end; IMyIntfC = interface procedure Hhh; {0} procedure Iii; {1} procedure Jjj; {2} end; IMyIntfD = interface(IMyIntfA) procedure Hhh; {7} procedure Iii; {8} procedure Jjj; {9} end; IMyIntfX = interface(IMyIntfA, IMyIntfC) // implizit über IMyIntfA enthalten //procedure Aaa; {0} //procedure Bbb; {1} //procedure Cee; {2} //procedure Ddd; {3} //procedure Eee; {4} //procedure Fff; {5} //procedure Ggg; {6} // implizit über IMyIntfC enthalten //procedure Hhh; {0} //procedure Iii; {1} //procedure Jjj; {2} // neue Methoden von IMyIntfX procedure Kkk; {7} procedure Lll; {8} procedure Mmm; {9} end; // aber jetzt gäbe es mehrfach gleiche Indize, // welches sich nicht adressieren ließen, // denn was wäre denn nun z.B. eine 1? // ok, also dann könnte Delphi theoretisch die Nummern "einfach" weiterzählen, IMyIntfY = interface(IMyIntfA, IMyIntfC) // implizit über IMyIntfA enthalten //procedure Aaa; {0} //procedure Bbb; {1} //procedure Cee; {2} //procedure Ddd; {3} //procedure Eee; {4} //procedure Fff; {5} //procedure Ggg; {6} // implizit über IMyIntfC enthalten //procedure Hhh; {7} //procedure Iii; {8} //procedure Jjj; {9} // neue Methoden von IMyIntfY procedure Kkk; {10} procedure Lll; {11} procedure Mmm; {12} end; // aber NEIN, dann würden die Indize nicht mehr mit denen vom IMyIntfC übereinstimmen IMyIntfA = das Ausgangsinterface IMyIntfB = enthält eigentlich einige Methoden von IMyIntfA, außer daß etwas vertauscht ist. Wenn man dieses also auf ein Interface vom Typ IMyIntfA anwendet, dann klappt daß, außer daß z.B. beim Aufruf von Eee intern das Ddd ausgeführt wird. IMyIntfC und IMyIntfD = die sehen eigentlich gleich aus, sind es aber nicht IMyIntfX und IMyIntfY = dieses geht zum Glück nicht, denn wie man sieht, stimmt da nix mehr. |
AW: Interfaces und Vererbung?
Also nochmal... nachdem ich jetzt an diesem Schullaptop versehentlich 2 mal den Tab geschlossen habe und den Text nicht mehr wieder herstellen konnte, versuche ich es ein weiteres mal.
Ich habe deine Erklärung jetzt glaube ich halbwegs verstanden, aber was ich nicht verstehe: Wieso kann man dann in einer Klasse mehrere voneinander unabhängige Interfaces implementieren?
Delphi-Quellcode:
type
IIntfA = interface procedure ProcA; {0} end; IIntfB = interface procedure ProcB; {0} end; TMyClass = class(IIntfA, IIntfB) procedure ProcA; procedure ProcB; end; |
AW: Interfaces und Vererbung?
Das ist doch gerade der Sinn von Interfaces.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:23 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