Hi Hagen
die beiden links sind gold wert
nach ein paar gemütlichen stunden mit dem debugger (*ironie*^^) habe ich erstmal die ganze genialität der sache regestriert^^
alles habe ich noch nicht raus....aber kommt noch
ich versuch es mal zusammenzufassen:
(ich hoffe du korrigierst mich falls ich irgendwas falsch interpretiere^^)
im grunde nutzen wir nur ein verhalten vom compiler das er bei Interfaces zeigt....
Interfaces wie sie hier benutzt werden sind im prinziep nur zeiger auf eine
VMT wobei uns der compiler ein haufen arbeit abnimmt....
im grunde kann man sie wie objekte/klassen verwenden....
1. locale interface variable
var MyIInteger: IInteger
hier wird MyIInteger auf dem stack angelegt und mit nil initialisiert
das besondere hierbei ist das sie mit nil intialiesiert wird was bei anderen localen var (z.B. Pointer, Integer) nicht der fall wäre, die haben irgendwelche werte die vorher auf dem stack lagen....
(das so erzeugte MyIInteger würde ich mir in gewisser weise als Pointer vorstellen)
2. funktions/procedur - aufrufe die so ein Interface als parameter haben
NSet(MyIInteger,1);
die funktionen testet ob MyIInteger nil ist
if @MyIInteger <> nil then......
wenn sie nil ist dann wird eine funktion aufgerufen die dem interface eine
VMT zuweist und speicher reserviert.... dazu komme ich gleich noch
wenn sie nicht nil ist hat sie eine
VMT und ist damit bereits initialisiert und kann verwendet werden....
3. zuweisungen
MyIInteger1:= MyIInteger2
hier ruft der compiler automatisch IntfCopy auf
procedure _IntfCopy(var Dest: IInterface; const Source: IInterface);
dadurch wird bei Dest der refcounter um 1 erhöht und MyIInteger1 auf die
VMT von MyIInteger2 geändert
und bei MyIInteger1 wird der refcounter um 1 verringert... fals er 0 wird, wird die
VMT und der speicher von MyIInteger1 frei gegeben
beide interface zeigen jetzt auf die selbe
VMT.....
dabei wird kein neuer speicher reserviert... halt wie bei Pointern
4. wenn der gültigkeitsbereich endet
also wenn das ende der funktion erreicht ist wird vom compiler automatisch IntfClear aufgerufen
function _IntfClear(var Dest: IInterface): Pointer;
dabei wird der refcounter von MyIInteger um eins verringert
wird er 0, wird die
VMT und der speicher von MyIInteger frei gegeben
auch bei
MyIInteger:= nil;
wird der refcount um 1 für die variable verringert
5. die
VMT (Virtual Methode Tabel)
jedes interface hat eine
VMT
Delphi-Quellcode:
type
IInterface = interface
['{00000000-0000-0000-C000-000000000046}']
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
end;
diese 3 methoden müßen von klassen die ein interface nutzen implementiert werden, das macht man am einfachsten in dem man TInterfacedObject als vorfahre der klasse mit einbindet
da unser interface MyIInteger in keine klasse eingebunden ist funktioniert das so nicht
deshalb müßen wir unsere
VMT mit den 3 funktionen selber machen
jede funktion die als übergabeparameter eines unserer interfaces hat, prüft ob das interface auf nil zeigt
ist das der fall reservieren wir speicher für ein pointerarray das min. 3 einträge hat
die 3 pointer müßen wir natürlich auf funktionen zeigen lassen die wir selber noch implementieren müssen... die im prinzip das machen was die standartfunktionen eines interfaces machen
außerdem können wir hier auch noch unsere eigenen methoden mit einbauen... indem wir die
VMT mit mehr einträgen machen (>3)
auch felder sind möglich, was bei normalen interfaces nicht möglich wäre
Fazit: der compiler übernimmt bei interfaces das was man bei normalen objecten mit create oder free selber machen müßte... man muß sich nicht um das aufräumen kümmern... speicherlecks sind eigentlich ausgeschlossen
allerdings muß man sich um die
VMT selber kümmern... das ist zwar im ersten augenblick komplizierter, aber wenn es einmal gemacht ist kann man nie wieder das freigeben oder erstellen von objekten vergessen
in c++ ruft der compiler automatisch den construktor für ein objekt auf wenn es als lokale variable verwendet wird...ebenso den destruktor (natürlich kann man hier auch noch den zeiger auf ein objekt verlieren und ein speicherleck bekommen...)
schade das sowas nicht bei delphie automatisch geht... darum der umweg über die interfaces
aber großes plus bei interfaces ist das refcounting
und kein TObject *juhu*
den overhaed den TObjekt verursacht... *omg*
da haben meine klassen wehniger eigene funktionen und felder als das was sie von TObject aufgedrückt bekommen....
eigentlich auch schade das man klassen nicht ohne TObjekt erstellen kann
andererseits hat die
VCL auch vorteile was besonders das
RAD betrifft... interaktionen mit dem benutzer der anwendung werden doch extrem vereinfacht...
naja, ist bissel verworen was ich da geschrieben habe... aber ich denke mal das es halbwegs richtig ist^^
ich schnapp mir morgen erstmal das
asm-buch.... hab mit tasm noch nix gemacht... nur masm... und da wird einiges anders sein bei pascal
lustig fand ich nur das ich die
asm-funktion von waitcursor schneller kapiert habe als das delphie-construckt^^
kleiner schneller sauberer
naja... ich lerne ja erst noch den delphi-syntax
mfg Dano