Fehlerhaftes Freigeben von Klassen mit Interfaces?

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
DelphiMarkus
Beiträge: 3
Registriert: Sa 23. Jun 2012, 16:36

Fehlerhaftes Freigeben von Klassen mit Interfaces?

Beitrag von DelphiMarkus »

Hallo liebes Lazarusforum!

Ich habe mich extra hier angemeldet um den Grund für das fehlerhafte Verhalten meines Projekts zu erfahren. Mein Problem ist, dass eine als Parameter übergebene 2. Klasse, die dann in der 1. Klasse mit dem Typ IVorschauDatenbank gehalten wird, durch ein ".Free" der 1. Klasse beschädigt bzw. auch freigegeben wird.
Ich habe mir extra ein kleines Beispielprojekt gebaut, dass eigentlich genau das gleiche Verhalten aufweisen sollte, wenn es wirklich ein Problem von Free Pascal ist. Aber dort habe ich kein Problem damit. Daher würde ich gerne wissen, wie es dazu kommt, dass bei dem einen Projekt dieses Problem auftritt.

Lazarus: SVN-Revision: 37602
FPC: 2.6.0

Es handelt sich um einen Vokabeltrainer, der Daten in einer SQLite-Datenbank speichert und dafür eine passende Klasse "TVokabelDatenbank" hat, die neue Vokabeln in die DB schreibt, usw. . Ich habe eine Import-Funktion eingebaut, die aber auch eine Vorschau anbietet. Ich habe mir gedacht, dass es doch da mal sinnvoll wäre ein Interface zu verwenden: "IVokabelHinzufuegen". Ich habe also TVokabelDatenbank und TVorschauDatenbank, die so definiert sind:

Code: Alles auswählen

{ uVokabelDatenbank.pas }
IVokabelHinzufuegen = interface(IInterface)
  procedure VokabelHinzufuegen(Vokabel: TVokabel);
end;
 
TVokabelDatenbank = class(TInterfacedObject, IVokabelHinzufuegen)
  {...}
public
  {...}
  procedure VokabelHinzufuegen(Vokabel: TVokabel);
end;
 
{ uImportVorschau.pas }
TVorschauDatenbank = class(TInterfacedObject, IVokabelHinzufuegen)
  {...}
public
  {...}
  procedure VokabelHinzufuegen(Vokabel: TVokabel);
  {...}
end;
Der komplette Quellcode befindet sich in Bitbucket (rev. 71): https://bitbucket.org/DelphiMarkus/voka ... 87cbcca93/ Die wichtigen Teile des Quellcodes poste ich hier aber trotzdem.

Die Klasse, die den Import erledigt sieht so aus:

Code: Alles auswählen

{ uImportExport.pas }
 
{TImporter}
TImporter = class
  private
    {...}
    FDatenbank: IVokabelHinzufuegen;
    {...}
  public
    {...}
    constructor Create(AEinstellungen: TImportEinstellung; CSV: TCSVDocument;
      Datenbank: IVokabelHinzufuegen);
end;
Wie man sieht ist "FDatenbank" vom Typ "IVokabelHinzufuegen". Ich muss sagen, dass mir das bisher eigentlich auch gut so gefällt. Es wäre schön, wenn ich es so beibehalten könnte.

Nun kommt aber erst das Problem, das ich nicht verstehe:

Code: Alles auswählen

procedure TfrmImport.btnVorschauClick(Sender: TObject);
var
  ImportEinstellung: TImportEinstellung;
  Importer: TImporter;
begin
  ImportEinstellung := ErstelleImportEinstellungen; // Ließt die Benutzereinstellungen ein
 
  // Importer erstellen und Importieren
  VorschauDatenbank.Leeren;
  Importer := TImporter.Create(ImportEinstellung, CSV, VorschauDatenbank);
  Importer.Importieren;
 
  frmImportVorschau.ListeAktualisieren;
  frmImportVorschau.ShowModal;
  Importer.Free;
  // ^ Hier wird die VorschauDatenbank gelöscht! DAS IST FALSCH!!!
  // Deswegen gibt es nun diese Zeile: v
  VorschauDatenbank := TVorschauDatenbank.Create;
end;
Wenn ich "Importer.Free" aufrufe, dann wird der Speicher des Importer-Objekts freigegeben und ich kann nicht mehr darauf zugreifen. Das klingt gut und ist auch richtig so. Das Problem ist aber, dass auch "FDatenbank" durch das Freigeben des Importers freigegeben wird. Dadurch kann ich danach nicht mehr darauf zugreifen, was bei der VorschauDatenbank hier sowieso egal ist. Deshalb hatte ich als ersten "Bugfix" (der aber keiner ist, wie mir jetzt erst klar wird) einfach die VorschauDatenbank neu erstellt. Wenn ich den Import nun statt mit der unwichtigen VorschauDatenbank mit meiner VokabelDatenbank mache, die überall im Projekt gebraucht wird, dann habe ich ein riesiges Problem, denn die VokabelDatenbank wird einfach zerstört. Dabei gehört sie zu den drei grundlegenden Teilen des Programms.
Ich könnte die VokabelDatenbank natürlich wie die VorschauDatenbank neu erstellen, aber das bekämpft nur die Symptome ohne das eigentliche Problem zu beseitigen. Auch könnte man die Vokabeln einer VorschauDatenbank auslesen und dann der VokabelDatenbank hinzufügen, aber warum nicht gleich die Vokabeln in die VokabelDatenbank eintragen, denn ein Umweg muss eigentlich nicht eingeschlagen werden.

Ich habe bisher im Internet auch nichts zu so einem Problem gefunden. Vielleicht liegt es daran, dass ich nicht wirklich weiß wonach ich suchen soll, aber dieser Fehler, wo auch immer er sein mag, ist wirklich ärgerlich.
"Gefixt" habe ich das Problem erstmal indem ich das Interface durch eine Klasse TVokabelHinzufuegen ersetze, die die procedure VokabelHinzufuegen als virtual und abstract definiert. Das geht zum Glück, weil die VokabelDatenbank von TObject erbt. Noch geht das, aber vielleicht muss ich später nochmal etwas ähnliches bauen, wo ich schließlich nicht um ein Interface herumkomme, wenn ich es einigermaßen schön lösen möchte.

Unter dem ersten Quelltextteil steht die Adresse zum kompletten Quellcode, vielleicht finden sich dort noch wichtige Hinweise.
Ich danke schon mal fürs Lesen und hoffe, dass zumindest einer von euch die Antwort auf das Problem kennt. Wenn noch Fragen da sind, beantworte ich sie gerne. :wink:

Vielen Dank,
Maximilian

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Fehlerhaftes Freigeben von Klassen mit Interfaces?

Beitrag von Socke »

Wie ist denn VorschauDatenbank deklariert? Es gibt da einen kleinen Unterschied zwischen Objekt- und Interface-Variablen:

Code: Alles auswählen

var
  o: TInterfacedObject;
  i: IUnknown;
begin
  o := TInterfacedObject.Create; // Refcount = 0
  i := TInterfacedObject.Create; // Refcount = 1
end; // Speicherleck: o wird nicht freigegeben
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

DelphiMarkus
Beiträge: 3
Registriert: Sa 23. Jun 2012, 16:36

Re: Fehlerhaftes Freigeben von Klassen mit Interfaces?

Beitrag von DelphiMarkus »

Hallo!

Die VokabelDatenbank wird in uMain.pas deklariert:

Code: Alles auswählen

var
  Datenbank: TVokabelDatenbank;
Und in uBenutzerWahl.pas in "TfrmBenutzerWahl.cbbDBChange" erzeugt:

Code: Alles auswählen

Datenbank := TVokabelDatenbank.Create(Einstellungen);
In einem FormDestroy wird die VokabelDatenbank dann manuell freigegeben. Ein Speicherleck entsteht dann ja nicht, aber mein Problem ist ja eher, dass beim Freigeben eines Objekts, das eine Referenz auf die Datenbank hat, auch die Datenbank freigegeben wird, obwohl das nirgens explizit im Code steht.

Ich habe übrigens ein kleines Beispiel gebastelt, das genau das gleiche Problem erzeugt:

Code: Alles auswählen

program freeInterfacedObjectTest;
 
{$mode objfpc}{$H+}
 
uses
  Classes, SysUtils;
 
 
type
 
  ITest = interface(IInterface)
    procedure Schreiben;
  end;
 
  TObjekt = class(TInterfacedObject, ITest)
    private
      FText: String;
    public
      procedure Schreiben;
 
      constructor Create(AText: String);
  end;
 
  TKlasse = class(TObject)
    private
      FObjekt: ITest;
 
    public
      procedure TueWas;
 
      constructor Create(Objekt: TObjekt);
  end;
 
{ TObjekt }
 
procedure TObjekt.Schreiben;
begin
  writeln(FText);
end;
 
constructor TObjekt.Create(AText: String);
begin
  FText := AText;
end;
 
{ TKlasse }
 
procedure TKlasse.TueWas;
begin
  FObjekt.Schreiben;
end;
 
constructor TKlasse.Create(Objekt: TObjekt);
begin
  FObjekt := Objekt;
end;
 
 
var
  Klasse1, Klasse2: TKlasse;
  Objekt: TObjekt;
 
begin
  writeln('Ein kleiner Test mit Objekten und Klassen');
 
  Objekt := TObjekt.Create('Hi');
  Objekt.Schreiben; // writeln geht
 
  Klasse1 := TKlasse.Create(Objekt);
  Klasse2 := TKlasse.Create(Objekt);
 
  Klasse1.TueWas; // writeln geht
 
  Klasse2.TueWas; // writeln geht
  Klasse2.Free;
 
  Klasse1.TueWas; // writeln geht
  Klasse1.Free;
 
  Objekt.Schreiben; // writeln geht nicht -> EAccessViolation : Access violation
  Objekt.Free;
end.

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Fehlerhaftes Freigeben von Klassen mit Interfaces?

Beitrag von Socke »

DelphiMarkus hat geschrieben:In einem FormDestroy wird die VokabelDatenbank dann manuell freigegeben. Ein Speicherleck entsteht dann ja nicht, aber mein Problem ist ja eher, dass beim Freigeben eines Objekts, das eine Referenz auf die Datenbank hat, auch die Datenbank freigegeben wird, obwohl das nirgens explizit im Code steht.
Das mit dem Speicherleck war auf meinen kurzen Code bezogen, da hier das erste Objekt nicht freigegeben wird. Nun zur Theorie:

Die Zählvariable für die Referenzen eines Objektes wird immer dann hochgezählt, wenn du ein Interface von diesem Objekt zuweist. Weist du das Objekt selbst an eine andere Variable zu, hast du natürlich eine Referenz mehr, aber du hast kein Interface verwendet. Daher wird hier auch die Zählvariable nicht erhöht.

Nachdem du die Vokabeldatenbank (TVorschauDatenbank) erstellt und in einer Variablen gespeichert hast, ist die Zählvariable gleich 0. Verwendest du nun ein Interface dieses Objektes (In einem Objekt der Klasse TImporter), wird auch die Zählvariable erhöht. Nun wird der Importer freigegeben und die Zählvariable wird wieder verringert.

Bei jedem Verringern der Zählvariable wird überprüft, ob diese kleiner oder gleich 0 ist. Wenn ja, wird das Objekt freigeben.
Du musst also unmittelbar nachdem du die Vokabeldatenbank erstellt hast die Zählvariable um 1 erhöhen, damit auch die Objektvariable als Referenz mitgezählt wird.

In deinem Beispiel geht das so:

Code: Alles auswählen

writeln('Ein kleiner Test mit Objekten und Klassen');
 
  Objekt := TObjekt.Create('Hi');
  Objekt.Schreiben; // writeln geht
 
  IUnknown(Objekt)._AddRef; // Zählvariable erhöhen
  objekt.Schreiben;
 
  Klasse1 := TKlasse.Create(Objekt);
  Klasse2 := TKlasse.Create(Objekt);
 
  Klasse1.TueWas; // writeln geht
 
  Klasse2.TueWas; // writeln geht
  Klasse2.Free;
 
  Klasse1.TueWas; // writeln geht
  Klasse1.Free;
 
  Objekt.Schreiben; // writeln geht nicht -> EAccessViolation : Access violation
  IUnknown(Objekt)._Release;  // Zählvariable verringern _und_ Objekt freigeben
In deinem Beispiel kannst du die Writeln-Zeile durch diese ersetzen; dann wird die Zählvariable mit ausgegeben.

Code: Alles auswählen

writeln(FText, ' ', Self.RefCount);
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

DelphiMarkus
Beiträge: 3
Registriert: Sa 23. Jun 2012, 16:36

Re: Fehlerhaftes Freigeben von Klassen mit Interfaces?

Beitrag von DelphiMarkus »

Hi!

Ich glaube, jetzt hab ich das endlich verstanden. Also:
Beim Erstellen des Objekts (TVokabelDatenbank / TVorschauDatenbank) wird die Anzahl der Referenzen des Interfaces (IVokabelHinzufuegen) nicht erhöht. Das Interface "denkt" also, dass es keine Referenzen gibt. Da das Interface aber nicht "angestoßen" wird, nachzusehen ob alle Referenzen weg sind, passiert einfach nichts. Das Objekt existiert weiterhin.
Wenn ich das Objekt nun z.B. in einer Variable mit dem Typ des Interfaces speichere, wird die Referenzanzahl auch hochgezählt.
Wenn ich nun ein Objekt freigebe, dass eine Variable mit dem Typ des Interfaces hat, dann tritt das Interface in Aktion, dekrementiert die Referenzanzahl, "merkt" dann, dass keine Referenzen mehr vorhanden sind, und löscht das Objekt bzw. gibt den Speicher frei. Obwohl ja eigentlich noch eine Referenz da ist, nur wurde die ja ganz am Anfang nicht mitgezählt.

Die Lösung wäre also, dass ich die Anzahl der Referenzen (wenn man so will: künstlich) erhöhe, damit das Objekt nicht freigegeben wird, wenn ich es nicht will.

Es ist echt interessant, dass das so funktioniert, denn das hätte ich mir (zumindest von Pascal bzw Objekt Pascal) nicht träumen lassen. Für mich ist Pascal eigentlich immer eine "dumme" Sprache, die nichts automatisch macht, gewesen. Das ist ganz und gar nicht böse gemeint, denn genau das finde ich so schön an Pascal.
Vielen Dank Socke!

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Fehlerhaftes Freigeben von Klassen mit Interfaces?

Beitrag von Socke »

Genau so ist das.
DelphiMarkus hat geschrieben:Für mich ist Pascal eigentlich immer eine "dumme" Sprache, die nichts automatisch macht, gewesen. Das ist ganz und gar nicht böse gemeint, denn genau das finde ich so schön an Pascal.
Wenn du eine wirklich dumme Sprache suchst, schau dir C an. Die modernen Pascal Dialekte wie Free Pascal oder Delphi sind da meilenweit von entfernt. Solche Dinge wie automatische Referenzzählung von unter anderem Strings, Interfaces und Arrays macht Pascal so angenehm und einfach. Denn das sind einfach nur lästige Dinge, die sowieso immer gleich sind und einfach im Denken aufhalten.

Auf der anderen Seite kann man Pascal fast genau so primitiv wie C machen indem man nur die Unit System (wird automatisch eingebunden) verwendet. :twisted:
DelphiMarkus hat geschrieben:Vielen Dank Socke!
Gern geschehen.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Patito
Beiträge: 203
Registriert: Di 22. Sep 2009, 13:08
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: Fehlerhaftes Freigeben von Klassen mit Interfaces?

Beitrag von Patito »

Socke hat geschrieben: Wenn du eine wirklich dumme Sprache suchst, schau dir C an. Die modernen Pascal Dialekte wie Free Pascal oder Delphi sind da meilenweit von entfernt. Solche Dinge wie automatische Referenzzählung von unter anderem Strings, Interfaces und Arrays macht Pascal so angenehm und einfach. Denn das sind einfach nur lästige Dinge, die sowieso immer gleich sind und einfach im Denken aufhalten.
Naja, ich würde nicht sagen, dass die automatische Refernzzählung von Interfaces irgendwie angenehm oder intelligent ist.
"Dummer Designfehler von Borland" trifft den Sachverhalt wohl am ehesten. Man muss jetzt eben mit diesem automatischen Ballast leben und
gelegentlich auch mal viel Code schreiben um den Unfug wieder geradezubiegen.

In Pascal muß man als Neuling erst mal den ganzen unsichtbaren Automatismus im Detail verstanden haben bevor man in der Lage ist Interfaces sinnvoll und gefahrlos einzusetzen... irgendwie ist das einfach nur das Gegenteil von gutem Sprach-Design.

P.S: Zum Glück kann man das RefCounting ausschalten (ist aber leider nicht standard):

Code: Alles auswählen

{$Interfaces CORBA}
  ITest = interface
    function Test: Integer;
  end;
 
  TTest = class(TInterfacedObject, ITest)
  public
    function Test: Integer;
  end;
 
procedure TForm1.Button1Click(Sender: TObject);
var t: TTest;
    it: ITest;
begin
     t := TTest.Create;
     it := t;
     it.Test;
     it := nil;
     t.Free; // Refcounting wurde ausgeschaltet -> kein Problem
end;
Zuletzt geändert von Lori am Mo 25. Jun 2012, 17:46, insgesamt 1-mal geändert.
Grund: richtiger Highlighter

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Fehlerhaftes Freigeben von Klassen mit Interfaces?

Beitrag von Socke »

Patito hat geschrieben:Naja, ich würde nicht sagen, dass die automatische Refernzzählung von Interfaces irgendwie angenehm oder intelligent ist.
"Dummer Designfehler von Borland" trifft den Sachverhalt wohl am ehesten. Man muss jetzt eben mit diesem automatischen Ballast leben und
gelegentlich auch mal viel Code schreiben um den Unfug wieder geradezubiegen.
Nach meinen wenigen Erfahrungen geht das immer gut, solange man keine wilden Code-Konstrukte verwendet. Alles andere schiebe ich jetzt mal auf falsches Anwendungsdesign :P.
Patito hat geschrieben:P.S: Zum Glück kann man das RefCounting ausschalten (ist aber leider nicht standard):
Warum du dann aber noch von TInterfacedObject ableitest kannst du nicht erklären?
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Patito
Beiträge: 203
Registriert: Di 22. Sep 2009, 13:08
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: Fehlerhaftes Freigeben von Klassen mit Interfaces?

Beitrag von Patito »

Socke hat geschrieben: Nach meinen wenigen Erfahrungen geht das immer gut, solange man keine wilden Code-Konstrukte verwendet. Alles andere schiebe ich jetzt mal auf falsches Anwendungsdesign :P.
Nach meiner Erfahrung geht RefCounting nur bei sehr simplen Anwendungsfällen gut (die man gut ohne Interfaces hätte erledigen können...).
Warum du dann aber noch von TInterfacedObject ableitest kannst du nicht erklären?
War doch nur ein Beispiel... ist doch für die Funktionsweise von "$Interfaces CORBA" egal. Dein Tonfall gefällt mir irgendwie nicht.

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Fehlerhaftes Freigeben von Klassen mit Interfaces?

Beitrag von Socke »

Patito hat geschrieben:Nach meiner Erfahrung geht RefCounting nur bei sehr simplen Anwendungsfällen gut (die man gut ohne Interfaces hätte erledigen können...).
Nun ja ... was soll ich dazu sagen? Dazu kenne ich deine Erfahrungen nicht.
Patito hat geschrieben:
Warum du dann aber noch von TInterfacedObject ableitest kannst du nicht erklären?
War doch nur ein Beispiel... ist doch für die Funktionsweise von "$Interfaces CORBA" egal. Dein Tonfall gefällt mir irgendwie nicht.
Da hast du auch Recht. Hiermit entschuldige ich mich dafür!
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Fehlerhaftes Freigeben von Klassen mit Interfaces?

Beitrag von mse »

Patito hat geschrieben:
Socke hat geschrieben: Nach meinen wenigen Erfahrungen geht das immer gut, solange man keine wilden Code-Konstrukte verwendet. Alles andere schiebe ich jetzt mal auf falsches Anwendungsdesign :P.
Nach meiner Erfahrung geht RefCounting nur bei sehr simplen Anwendungsfällen gut (die man gut ohne Interfaces hätte erledigen können...).
+1.
Hoch lebe {$interfaces corba} !

Martin

Patito
Beiträge: 203
Registriert: Di 22. Sep 2009, 13:08
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: Fehlerhaftes Freigeben von Klassen mit Interfaces?

Beitrag von Patito »

Socke hat geschrieben: Da hast du auch Recht. Hiermit entschuldige ich mich dafür!
Danke, war von mir auch nicht bös gemeint. Im Internet geht es eben meistens etwas rau zu.

Ich hab gerade mal gesucht, aber einen gute Doku-Referenz zum Thema {$Interfaces CORBA} habe ich noch nicht gefunden.
http://www.freepascal.org/docs-html/ref ... 9-990007.5" onclick="window.open(this.href);return false;
Ist schon sehr spartanisch, und Sätze wie:
"it specifies what the parent interface is of an interface, declared without parent."
stimmen wörtlich genommen so nicht. (Auch mit CORBA hat man Interface-Vererbung)

Allein schon die Bezeichnungen COM und Corba sind unglücklich gewählt.
- COM und Corba sind ja Prozess-Kommunikation
- Interfaces sind Sprachfeatures innerhalb einer Anwendung (~interne Kommunikation).
Mit Corba an sich hat das ganze ja gar nichts zu tun.

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Fehlerhaftes Freigeben von Klassen mit Interfaces?

Beitrag von Socke »

Patito hat geschrieben:"it specifies what the parent interface is of an interface, declared without parent."
stimmen wörtlich genommen so nicht. (Auch mit CORBA hat man Interface-Vererbung)
Eigentlich schon: Es bestimmt, welches Elterninterface Interfaces haben, bei denen du keine expliziten Angaben machst. Um diesen Satz zu verstehen braucht man natürlich (einiges) Hintergrundwissen aus dem Thema (wie du zu Recht anmerkst).
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Fehlerhaftes Freigeben von Klassen mit Interfaces?

Beitrag von mse »

Patito hat geschrieben: Ich hab gerade mal gesucht, aber einen gute Doku-Referenz zum Thema {$Interfaces CORBA} habe ich noch nicht gefunden.
http://www.freepascal.org/docs-html/ref ... 9-990007.5" onclick="window.open(this.href);return false;
Ist schon sehr spartanisch, und Sätze wie:
"it specifies what the parent interface is of an interface, declared without parent."
stimmen wörtlich genommen so nicht. (Auch mit CORBA hat man Interface-Vererbung)

Code: Alles auswählen

type
 {$interfaces corba}
 mycorbainterface = interface
  //dieses interface hat keine impliziten vorfahren und keine compiler magic
  //zur referenzzählung
 end;
 {$interfaces com}
 mycominterface = interface 
  //dies entspricht  mycominterface = interface(iunknown) und aktiviert
  //compiler magic zur referenzzählung
 end;
iunknown ist definiert als:

Code: Alles auswählen

IUnknown = interface
         ['{00000000-0000-0000-C000-000000000046}']
         function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
         function _AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
         function _Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
       end;
Allein schon die Bezeichnungen COM und Corba sind unglücklich gewählt.
Woher die Bezeichnung corba stammt scheint nicht mehr so klar zu sein:
http://bugs.freepascal.org/view.php?id=6036
- COM und Corba sind ja Prozess-Kommunikation
- Interfaces sind Sprachfeatures innerhalb einer Anwendung (~interne Kommunikation).
Mit Corba an sich hat das ganze ja gar nichts zu tun.
Wobei FPC COM interfaces unter Windows tatsächlich zur Prozesskommunikation verwendet werden können. Bei Corba war es vermutlich angedacht.
Wichtig in diesem Zusammenhang auch:
http://bugs.freepascal.org/view.php?id=14024
http://www.freepascal.org/docs-html/ref ... -1000007.6

Martin

Antworten