Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Mo Jul 14, 2025 15:49

Foren-Übersicht » Programmierung » Allgemein
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 10 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Interface Problem[gelöst]
BeitragVerfasst: So Mai 03, 2009 11:03 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Jan 31, 2007 18:32
Beiträge: 150
Programmiersprache: Pascal
Code:
  1.  
  2. type
  3. IMyInterface =  interface (IInterface)
  4.   ...
  5. End;
  6.  
  7. TMyObject = class(TInterfacedObject)
  8.    procedure Update; virtual; abstact;
  9.    ...
  10. End;
  11. TMyInterfacedObject = class (TMyObject, IMyInterface)
  12.    procedure Update; override;
  13.    ...
  14. End;
  15.  
  16. procedure TMyInterfacedObject.Update;
  17. Begin
  18.   // do sth.
  19. End;
  20.  
  21. var abc : TMyInterfacedObject;
  22.       List : TList;
  23. Begin
  24.     abc := TMyInterfacedObject.Create;
  25.     List.Add(abc);
  26.     TMyObject (List[0]).Update;
  27.     ...
  28. End;
  29.  


Darf ich das?? Wenn nein irgendwelche Tipps wie ich das umgehen könnte??


Zuletzt geändert von FrenK am So Mai 03, 2009 11:05, insgesamt 1-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Mai 03, 2009 11:05 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Jan 31, 2007 18:32
Beiträge: 150
Programmiersprache: Pascal
Ja ich darf das XD habe gerade festgestellt, dass das Problem an einer anderen Stelle lag und jetzt läuft alles wieder einwandfrei...


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Mai 04, 2009 08:17 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Dürfen tust du das sicherlich. Nur mir stellt sich die Frage ob du das auch tun solltest? Die Methode Update ist virtuell abstrakt und in der abgelitten Klasse auch schön überschrieben. Damit wird beim Aufruf die Methode die der abgelitten Klasse aufgerufen. Der klassische Weg mit dem Umgang von abstrakten Klassen zum Implementieren von variablen Codeteilen. So weit so gut. Nichts desto trotz halte ich die generelle vorhensweise für potentiell sehr gefährlich. Warum? Das Interface. TInterfacedObject implementiert eine Referenzzählung. Diese Zählung löscht deine Klasseninstanz sobald der Zähler 0 ist. Allerdings werden dort nur Interfacepointer gezählt. Also wenn du 20 Pointer auf die Klasseninstanz hast, dann ist der Zähler trotzdem 0. Sobald du jetzt ein mal ein Interface von der Klasse anforderst und das Interface wieder wegschmeißt, dann wird deine Klasseninstanz gelöscht. Ob du willst oder nicht. Und das schönste daran. Du merkst davon erst etwas, wenn du das nächste Mal auf dein bereits gelöschtes Objekt wieder zugreifen möchtest. Und das vermutlich nur, weil es dann zu einer Zugriffsverletzung kommt.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Mai 04, 2009 17:03 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Jan 31, 2007 18:32
Beiträge: 150
Programmiersprache: Pascal
Dieses Problem hab ich bereits bedacht und gelöst idem ich den Referentzähler im Constructor um 1 erhöhe und im Destructor entsprechend um 1 verringere dies hat die Folge, dass es erst dann wenn es auch soll freigegeben wird.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Mai 05, 2009 10:28 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Jan 04, 2008 21:29
Beiträge: 419
Wohnort: Lübeck
moin, kann mir das jemand mit dem Referenzzähler genauer erklären? Ich mach das mit den Interfaces nähmlich genaus so, hab aber bisher keine Fehler bekommen, evtl. aus Zufall, da würde ich gerne wissen wie das genau zu Stande kommt.

Danke schonmal und Grüße!

_________________
Klar Soweit?


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Mai 05, 2009 12:04 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
In dem Code FrenK stecken zwar Interfaces aber die werden nicht aktiv benutzt. Von daher könnte man sie eigentlich auch fast weglassen. Außer für eventuelle Mehrfachvererbung.

Aber Beispiel von dem was ich meinte.

Ein Interface und die dazugehörende Klasse. Was das Interface an funktionen anbietet ist für das Beispiel vollkommen egal.
Code:
  1. IBlah = Interface
  2. ...
  3. end;
  4.  
  5. TBlah = class(TInterfacedObject, IBlah)
  6. ...
  7. end;


Ein Beispiel wie Interfaces verwendet werden.
Code:
  1. var
  2.   Blah: IBlah;
  3. begin
  4.   Blah := TBlah.Create;
  5.   Blah. ...;
  6.   Blah := nil;  // nive to have
  7. end;


Normal erzeugt man eine Klasse und weißt diese auf eine Interfacevariable zu. Damit kennt blah nur noch die Funktionen die das Interface zur Verfügung stellt. Eventuelle andere Interfaces (Mehrfachvererbung) lassen sich entweder per Operator AS oder per Blah.QueryInterface zurückgeben. Es ist auch möglich eine Variable von TBlah zu erzeugen und dann die Variable auf die Interfacevariable zuzuweisen.

In jedem Fall wird aber bei der Zuweisung auf eine Interfacevariable intern _AddRef aufgerufen. Also die Klasseninstanz wird ein mal mehr verwendet. Erstellen wir noch eine zweite Interfacevariable, dann ein zweites mal. Usw. Wenn wir dann auf eine Variable nil zuweisen oder die Methode verlassen, dann wird _Release aufgerufen. Und der Zähler verringert. Ist der Zähler 0 wird innerhalb von _Release der Destruktor aufgerufen. Damit ist die Instanz weg.

Code:
  1. var
  2.   BlahC: TBlah;
  3.   Blah_1, Blah_2: IBlah;
  4. begin
  5.   // Klasse erstellt (RefCount = 0)
  6.   BlahC := TBlah.Create;
  7.  
  8.   // Interface wird erfragt (RefCount = 1)
  9.   Blah_1 := BlahC;
  10.  
  11.   // Interface wird erfragt (RefCount = 2)
  12.   Blah_2 := Blah_1;
  13.  
  14.   // Interface1 wird nicht mehr benötigt  (RefCount = 1)
  15.   Blah_1 := nil;
  16.  
  17.   // funktioniert noch, da noch 1 überlebender
  18.   BlahC.Blub;
  19.  
  20.   // Interface2 wird nicht mehr benötigt  (RefCount = 0)
  21.   Blah_2 := nil;
  22.  
  23.   // Hier knallt es, da die Instanz in der Zeile darüber gelöscht wurde.
  24.   BlahC.Blub;
  25. end;


Diese Zählung arbeitet nur mit dem Interfaceteil der Klasse zusammen. Variablen vom Typen TBlah werden nicht gezählt. Und dann kann es passieren, dass durch die Interfaces die Klasse einem unter dem Hinter weggelöscht wird. Das aber wiederrum bekommt man nicht mit. Die Instanz der Klasse sieht vollkommen okay. Eventuell existierende Pointer auf die Instanz sind nach wie vor vorhanden und enthalten noch den Pointer an der die Klassendaten mal lagen. Also so etwas wie Assigned wird sagen, dass alles okay ist. Vergleichbar wäre das in etwa auch wie folgt.

Code:
  1. var
  2.   Blah_1, Blah_2: TBlah;
  3. begin
  4.   // Klasse erstellt
  5.   Blah_1 := TBlah.Create;
  6.  
  7.   // zusätzlichen Instanzenpointer holen
  8.   Blah_2 := Blah_1;
  9.  
  10.   // Instanz freigeben
  11.   Blah_1.Free;
  12.   Blah_1 := nil;
  13.  
  14.   // kawummm
  15.   Blah_2.Blub;
  16. end;

Wobei man da nicht mal die Instanz wegseln müsste. Es reicht auch, wenn man Blah_1 nicht nil setzen würde. Der Effekt ist in allen Fällen der Gleiche.

PS: Das Kawumm oder die Zugriffsfehler müssen aber nicht immer auftreten. Die Klassen sind recht doof. Eine Klasseninstanz besteht nur aus einem Pointer auf Code und einem Pointer auf die Daten. Wenn die Daten freigegeben werden, dann bleibt der Wert an dieser Speicherstelle meistens noch gleich. Wenn man dann mit einer ungültigen Klasseninstanz auf Member zugreift, dann greift sie auf den freigegebenen Speicher zu. Dort stehen aber noch richtige Werte. Also passiert nichts schlimmes. Nur sobald jemand anderes Speicher haben will und sich die Bereiche überschneiden können echt lustige Dinge entstehen. Alternativ kann es auch passieren, dass der Speichermanager den Speicherblock komplett wieder an das Betriebsystem übergibt. Dann knallt es recht zuverlässig. (Invalid Pointer operation etc.) Also es muss nicht zwingend knallen. Wenn man Glück hat kann man noch eine halbe Stunde mit der Instanz weiterarbeitet ohne, dass was passiert. Das sind dann aber Fehler die besonders Heimtückisch sind.

PPS: Wenn ich neben dem Interface noch die Klasseninstanz benötige, dann würde mal ich persönlich mal stark überlegen ob Interfaces wirklich nötig sind und ob man das nicht eventuell durch eine reine Klassenstruktur lösen kann. Die richtige Struktur zu finden ist ja das schwierigste an OOP. Interfaces sehe ich eher nur da wo man die Schnittstelle von der Implementation trennen muss. Also wäre es möglich 2 komplette getrennte Klassenhirarchien zu machen die beide ein Interface anbieten womit man auf diverse Eigenschaften zugreifen kann. Dann würde man auskommen, wenn man das Interface benutzt. Alles andere wäre dann egal. Was aber im Endeffekt wieder nichts weiter als eine abstrakt Basisklasse ist. Nur eben kann eine Klasse mehrere Interfaces anbieten. Darf aber nur eine Basisklasse haben.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Mai 05, 2009 15:18 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Jan 04, 2008 21:29
Beiträge: 419
Wohnort: Lübeck
Also wenn ich das jetzt richtig verstanden habe, dann wird nur beim instanzieren eines Interfaces der RefCount inkrementiert, nicht beim instanzieren einer Klasse. Klingt irgendwie logisch.. oder so !? Auf der anderen Seite mus ich aber auch gestehen, das mir das Konstrukt, welches ich mit der Interface/Klassen kombination geschaffen habe selbst merkwürdig vorkommt und im nachhinein festgestellt habe, das ich das Interface garnicht gebraucht hätte.

_________________
Klar Soweit?


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Mai 05, 2009 16:08 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Jan 31, 2007 18:32
Beiträge: 150
Programmiersprache: Pascal
Zitat:
In dem Code FrenK stecken zwar Interfaces aber die werden nicht aktiv benutzt. Von daher könnte man sie eigentlich auch fast weglassen. Außer für eventuelle Mehrfachvererbung.


Richtig ich brauche das ganze für Mehrfachvererbung und dachte eben es könnte zu Problemen kommen wenn ich eine klasse von TInterfacedObject ableite, aber erst ein Nachfahre dieser Klasse benutzt eben Interfaces. Das eigene Problem lag daran, dass ich einen Pointer vergessen habe entsprechen zu incrementieren aber das hat sich ja wie bereits gesagt geklärt.

Um auf den Referentzzähler zurückzukommen ich hab bis jetzt 2 mögliche ansätze dieses Problem zu umgehen gefunden zum einen ein eigener Zähler zum anderen Manipulation des Zählers.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Mai 05, 2009 16:11 
Offline
Guitar Hero
Benutzeravatar

Registriert: Do Sep 25, 2003 15:56
Beiträge: 7810
Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Ist das ein delphispezifisches Problem? Ich hab bei Java viel mit Interfaces zu tun, und nie Probleme damit. Im Gegenteil, ich liebe diese Idee.

_________________
Blog: kevin-fleischer.de und fbaingermany.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Mai 05, 2009 19:05 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Flash hat geschrieben:
Ist das ein delphispezifisches Problem? Ich hab bei Java viel mit Interfaces zu tun, und nie Probleme damit. Im Gegenteil, ich liebe diese Idee.

Das ist kein Problem. Das ist von der Klasse TInterfacedObject so gewollt. Es geht bei Interfaces ja auch um solch eine Referenzzählung. Denn die werden benutzt und bei nicht mehr gebrauchen räumen sie sich selber weg. So wie das sein soll. Nur wenn man andere Teile dort mit einbezieht kanns Probleme geben.

Im übrigen muss man nicht InterfacedObject benutzen. InterfacedObject implementiert nur die 3 Methoden die für Interfaces benötigt werden. Also da könnte man auch eine Basis implementieren die ohne Zählung auskommt. Weil das ist ja eigentlich auch genau das was du jetzt so auch machst. Was aber eigentlich auch keine große Rolle spielt.


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 10 Beiträge ] 
Foren-Übersicht » Programmierung » Allgemein


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.015s | 17 Queries | GZIP : On ]