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

Aktuelle Zeit: So Jul 06, 2025 10:21

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



Ein neues Thema erstellen Auf das Thema antworten  [ 12 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: [Delphi] Pointer auf Hauptklasse
BeitragVerfasst: Mo Dez 17, 2007 10:13 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Jan 31, 2005 11:02
Beiträge: 432
Wohnort: Rheinlandpfalz
Hallo,
ich hab eine, vllt auch mehrere Fragen zu Pointern.
Angenommen ich habe so eine Klassen-Struktur:
Code:
  1. Type
  2.   TChildClass = Class(TObject)
  3.   Private
  4.   ...
  5.   Public
  6.   ...  
  7.   End;
  8.  
  9.   PMainClass = ^TMainClass;
  10.   TMainClass = Class(TObject)
  11.   Private
  12.     FChild     : TChildClass;
  13.     FIrgendwas : Integer;
  14.     ...
  15.   Public
  16.   ...  
  17.   End;

So, jetzt will ich, dass die ChildClass auf die MainClass zugreifen kann (auch auf den Private-Teil).
Dazu gibt es ja verschiedene Möglichkeiten:


1.
Ich speichere in der Private-Section der ChildClass einen Pointer vom Typ PMainClass auf die Hauptklasse (FParent),
welchen ich bei TChildClass.Create(hier) mitgebe. Dann kann ich immer, wenn ich Zugriff brauche,
mit
Code:
  1. FParent.FIrgendwas  := 12;
  2. FParent^.FIrgendwas := 10; // geht auch, -> was ist der Unterschied??



2.
Ich übergebe beim Createn der ChildClass einen Pointer vom Typ Pointer auf die Hauptklasse, speicher diesen im Private-Teil der ChildClass ab (FParent) und den ich, wenn ich Zugriff auf die Hauptklasse aus einer Child-Methode brauche, wie folgt benutze:
Code:
  1. Procedure TChildClass.DoSomething();
  2. Var
  3.   ParentClass : TMainClass;
  4. Begin
  5.   ParentClass := TMainClass(FParent);
  6.   ParentClass.FIrgendwas := 4;
  7. End;



3.
Ich übergebe jedesmal, wenn ich in einer Methode der ChildClass Zugriff auf die MainClass brauche, einen Pointer vom Typ PMainClass mit:
Code:
  1. Procedure TChildClass.DoSomething(Parent: PMainClass);
  2. Begin
  3.   Parent^.FIrgendwas := 4;
  4. End;



Sicherlich gibt es noch andere (bessere?) Möglichkeiten.
Was mir jetzt aufgefallen ist:
- Nicht immer geht die 1. Möglichkeit. Manchmal bekomme ich Access-Violations. Warum?!
- Methode Nr.2 geht immer, ist aber etwas aufwändig.
- Methode Nr.3 geht auch immer, ist aber noch aufwändiger...

Weiß jemand warum meine Methode Nr.1 nicht immer geht? Ich würde es gerne verstehen.
Außerdem:
- Gibt es eine bessere Möglichkeit?
- Macht ihr es irgendwie anders?
- Braucht ihr sowas nicht?


Sind doch mehrere Fragen geworden ;)
Ich hoffe ihr könnt da etwas Klarheit rein bringen.

Danke für Antworten,
MatReno

_________________
http://texelviews.delphigl.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Dez 17, 2007 11:41 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Als erstes ein Mal. Klasseninstanzen sind bereits Pointer als vergiss bitte ganz schnell die Pointer auf Klassen! Das ist pfui bäh und führt eher nur zu Problemen. ;) Es macht sicher in der ein oder anderen Situation Sinn oder ist dann notwendig. Allerdings versuche ich so etwas nach Möglichkeit immer zu vermeiden.

Um deine Definitonen anzupassen muss ja lediglich jede Klasse die andere kennen. Dazu gibt es Forward Deklarationen. Dann kannst du die ganze Zeit mit echten Typen arbeiten. Also sowohl im Konstruktor als auch überall anders. Das sieht dann in etwa so aus. Und dann kennt die TChildClass auch die TMainClass. Die Main kennt die Child ja sowieso, da sie nach ihr deklariert wurde.
Code:
  1. type
  2.   TMainClass = class; // forward
  3.  
  4.   TChildClass = class
  5.   private
  6.     fMain: TMainClass;
  7.   end;
  8.  
  9.   TMainClass = class
  10.   private
  11.     fChild: TChildClass;
  12.   end;

Allerdings eine kleiner Ermahnung/Anregung. Wenn die Klassen sich gegenseitig benötigen deutet das meistens auf ungut durchdachtes Klassenkonzept hin. Denn Klassen sollten Modular sein und somit wären sie eher ziemlich stark miteinander verzahnt. Es passiert schon mal, dass man in solche Situationen kommt. Aber es deutet eher auf eine Schwachstelle des Konzeptes hin. Also sollte so etwas schon recht gut überlegt sein. Das aber nur als Anregung.

1. Der Unterschied zwischen beiden Methoden ist folgender: Keiner. Zu mindest derefenziert Delphi automatisch sobald es ein typisierter Pointer ist. Allerdings verlasse ich mich da nicht drauf. Ich dereferenziere grundsätzlich IMMER selber. Alleine auch schon dadurch, dass ich auf den ersten Blick sehe ob es ein Pointer ist oder nicht. Der ein oder andere lässt das lieber Delphi erledigen. Ist Geschmackssache. Aber mir persönlich gefällt das Automatische nicht.

2 und 3. Siehe oben. ;)


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Dez 17, 2007 12:28 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2623
Wohnort: Berlin
Programmiersprache: Go, C/C++
Ich bevorzuge ebenfalls die Variante, die Lossy eX gepostet hat.
So kann man einfach beim erstellen oder über nen Property Parent die Elternklasse sauber festlegen.

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Dez 17, 2007 12:32 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Dem Stimme ich zu. Mache ich bei meinen Listen-Klassen auch immer so:

Code:
  1.  
  2. type
  3.   TListItem = class;
  4.   TListClass = class;
  5.  
  6.   TListItem = class (TObject)
  7.     constructor Create(AParent: TListClass);
  8.   private
  9.     FParent: TListClass;
  10.   public
  11.     property Parent: TListClass read FParent;
  12.   end;
  13.  
  14.   TListClass = class (TObject)
  15.   public
  16.     function AddItem: TListItem;
  17.   end;
  18.  


Gruß Lord Horazont

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Dez 17, 2007 15:02 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Jan 31, 2005 11:02
Beiträge: 432
Wohnort: Rheinlandpfalz
Ich hat geschrieben:
Was mir jetzt aufgefallen ist
- Nicht immer geht die 1. Möglichkeit. Manchmal bekomme ich Access-Violations. Warum?!

Wisst ihr warum das manchmal nicht geht? Das hab ich nämlich irgendwo drin, da funzt es, aber in anderen Situationen hat diese Technik mich völlig im Stich gelassen... Es regnete nur so AV's :wink:

// EDIT:
Fast vergessen: Danke für die Antworten!

_________________
http://texelviews.delphigl.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Dez 17, 2007 16:10 
Offline
Ernährungsberater
Benutzeravatar

Registriert: Sa Jan 01, 2005 17:11
Beiträge: 2068
Programmiersprache: C++
Methode 1 sollte immer klappen, das einzige was passieren könnte das ab und an aus dem Pointer auf Pointer Probleme auftreten.

_________________
Steppity,steppity,step,step,step! :twisted:
❆ ❄ ❄ ❄ ❅ ❄ ❆ ❄ ❅ ❄ ❅ ❄ ❅ ❄ ❄
❄ ❄ ❄ ❅ ❄ ❄ ❄ ❅ ❄ ❄ ❆ ❄ ❄


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Dez 17, 2007 16:51 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Na ja. Wollte auch gerade sagen, dass es immer klappen sollte. Aber wenn man sich mal genau betrachtet was da passiert wird es offentsichtlich. Denn typischerweise würde der Code folgendermaßen aussehen.
Code:
  1. type
  2.   PMyClass = ^TMyClass;
  3.   TMyClass = class (TClass);
  4.  
  5. procedure Add(Blah: PMyClass);
  6. begin
  7.   FBlah: Blah;
  8. end;
  9.  
  10. procedure Bloek;
  11. var
  12.   Blah: TMyClass
  13. begin
  14.   Blah := TMyClass.Create;
  15.  
  16.   Add(@Blah);
  17.   // oder Addr(Blah) Ist das Gleiche.
  18. end;

Das nur mal als Beispiel. Sollte ja vom Prinzip her gleich sein. Aber was passiert da jetzt? Es wird der Pointer der Variable Blah übergeben. Da Add sich den Pointer einer lokalen Variable merkt ist dieser Pointer nur so lange gültig wie die Variable gültig ist. Also nur so lange wie die Methode Bloek ausgeführt wird. Nach dem Ende der Methode ist diese Variable nicht mehr existent. Es kann dennoch passieren, dass der Inhalt an dieser Speicherstelle noch nicht überschrieben wurde. Das muss aber nicht. Spätestens das nächste mal wenn eine Methode etwas, an dieser Stelle, auf den Stack packt wurde sie überschrieben. Und dann bekommst du eine Zugriffsverletzung. Obwohl die Klasseninstanz weiterhin intakt ist. Aber der Speicher an dem der Pointer von ihr steht wurde überschrieben.

Bei direkter Benutzung wird die Adresse immer sauber kopiert weswegen so etwas nicht passiert. Um das auch zu rreichen hätte man also den Speicherbereich von Blah schon mit GetMem alloziieren müssen. Ansonsten ist es ein reine Glücksspiel und nur eine Frage wann es knallt. Ob es knallt steht dabei nicht mehr zur Debatte. Außer man weiß wirklich sehr genau wie lange der Pointer gültig ist. Aber beim Zwischenspeichern und später Benutzen wurde die Gültigkeit definitv überschritten.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Dez 17, 2007 17:08 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Jan 31, 2005 11:02
Beiträge: 432
Wohnort: Rheinlandpfalz
Ok verstehe... Danke.
Werde jetzt alles so machen, wie ihr (forward-declaration).
Hab schon einiges umgebaut und es funktioniert wunderbar. :P

_________________
http://texelviews.delphigl.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Dez 18, 2007 21:38 
Offline
DGL Member

Registriert: Di Jun 06, 2006 09:59
Beiträge: 474
Solange beide in der selben unit sind geht es doch sowieso, und wenn sie in verschiedenen sind, wieso nimmst du dann nicht einfach protected?

_________________
Bild


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Dez 19, 2007 09:17 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Öhm. Ich weiß jetzt nicht was protected mit verschiedenen Units zu tun hat? Eigentlich regelt protected ja "nur" die Zugriffsrechte. ;) 2 Klassen die sich gegenseitig Verwendung und in unterschiedliche Units stecken resultieren grundsätzlich immer in einer zirkulären Referenz, da beide Klassen jeweils die Andere bereits im Interface benötigen. So etwas kann man nur lösen in dem man durch diverse Klassenumstellerreien etc. (die Liste an Feinheiten ist lang) die eine Unit aus dem Interface bekommt. Also in dem man verhindert, dass sie sich direkt benutzen.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Dez 20, 2007 11:42 
Offline
DGL Member

Registriert: Di Jun 06, 2006 09:59
Beiträge: 474
ok ich habe ihn falsch verstanden, ich meine dass er auf die privateelemente der anderen klasse zugreifen will. Zirkulaere Abhaenigkeiten auf Klassenebene kann man so natuelich nicht loesen.

Zitat:
Allerdings eine kleiner Ermahnung/Anregung. Wenn die Klassen sich gegenseitig benötigen deutet das meistens auf ungut durchdachtes Klassenkonzept hin. Denn Klassen sollten Modular sein und somit wären sie eher ziemlich stark miteinander verzahnt. Es passiert schon mal, dass man in solche Situationen kommt. Aber es deutet eher auf eine Schwachstelle des Konzeptes hin. Also sollte so etwas schon recht gut überlegt sein. Das aber nur als Anregung.

Wieso sind parent-child Beziehungen (Ueblicherweise der Hauptgrund fuer solche abhaengigkeiten) schlechtes Design?

_________________
Bild


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Dez 20, 2007 12:42 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Child-Parent Beziehungen. Ich habe bewusst nicht schlechtes Design geschrieben. Denn das ist es eigentlich nicht. Bzw liegt so etwas sehr stark im Auge des Betrachters. Und ich bin jemand der sehr sehr stark auf so etwas setzt. Zu mindest meistens. ;) Ich meinte damit aber die extreme Verzahnung von unterschieldichen Klassen. Bei der Objektorientierten Programmierung geht es ja nicht nur darum Klassen zu benutzen. Sondern diese auch entsprechend modular zu gestalten.

Also sollten die Klassen bewusst so gestaltet werden, dass diese sich nur um ihre eigenen Sachen/Aufgaben kümmern. Wenn aber verschiedene Klassen Zugriff auf alles Mögliche haben, dann kann das darauf deutet, dass deren Aufgabenbereiche nicht klar geregelt ist. Außer deren Aufgabe ist die Verwaltung von Allem. Einer Bierflasche ist es ja schließlich auch egal wo sie sich im Kasten befindet und welche Farbe dieser hat. Aber deine Anmerkung ist auch berechtigt. Es kommt auch stark auf den einzelnen Fall an. Speziell bei baumartigen Strukturen benötigen die Kinder fast immer (sehr häufig) Informationen über das übergeordnete Element. Wobei das häufiger auch eher um die Verwaltung von Außen geht als darum, dass die Kinder auf die übergeordneten Elemente selber zugreifen müssen.

Man sollte sich nur generell gut überlegen ob das so auch Sinn macht. Denn der häufig aufgezählte Vorteil von OOP liegt ja in der Modularität und in der Wiederverwertbarkeit des Codes. Wenn die Klassen aber zu stark miteinander verbunden sind, dann lässt sich so etwas nur schwer durchsetzen. Das Ganze bezieht sich nicht nur auf die Anordnung der Klassen sondern auch welche Eigenschaften/Methoden sie zur Verfügung stellen/weiter reichen. Denn das beeinflusst maßgeblich die Struktur und das Zusammenwirken von Allem.


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


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 6 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.009s | 14 Queries | GZIP : On ]