![]() |
Klasse oder Record auf sich selbst?
Was ich möchte steht bestimmt schon irgendwo im Forum nur finde ich es nicht. Vielleicht habe ich auch nur einen Denkfehler. Ich möchte ein Record (oder Klasse egal) erzeugen, die wiederum sich als Eigenschaft hat. Ich dachte damit kann ich so eine Art Hierarchie erzeugen, so ähnlich wie es bei XML ist.
Delphi-Quellcode:
Oder macht man das ganz anders?
TGroups = class(TObject)
id: Integer; name: String; main: Integer; fgroup_sorted: Boolean; SubGroups: Array of TGroups; end; |
Re: Klasse oder Record auf sich selbst?
Zitat:
TComponent hat die Properties Components[] und ComponentCount. Damit kann jedes TComponent-Objekt beliebig viele Unterkomponenten enhalten. |
Re: Klasse oder Record auf sich selbst?
Das ist soweit ok, allerdings würde ich mindestens noch einen Destruktor spendieren, der die enthaltenen Objekte freigibt. Und ich würde die Eigenschaften besser schützen, das ist ja gerade der Vorteil einer Klasse gegenüber einem Record.
|
Re: Klasse oder Record auf sich selbst?
Zitat:
kein Problem mit einer Klasse, und gut geeignet für Baumstrukturen. Beispiel:
Delphi-Quellcode:
Hier wird nur das Root-Objekt erzeugt und eine XML-artig strukturierte (Text)Datei übergeben, dann erzeugen sich die Objekte selbst (abhängig von ObjCode) bis die Datei abgearbeitet ist.
type
TCPAObject = class; TCPARootObject = class; TCPADataObject = class ObjCode : TCPACodeStr; Root : TCPARootObject; Parent : TCPADataObject; Next : TCPADataObject; KeyWord : TCPAKeyWordStr; Depth : integer; {$IFDEF DebugWindow} SeqNumber : integer; {$ENDIF} constructor create (pRoot : TCPARootObject; pParent : TCPAObject); procedure GetNextObject (var CO : TCPADataObject); end; TCPAObject = class (TCPADataObject) SubKeyWord : TCPAKeyWordStr; ItemNumber,StringNumber : integer; ActDetail : TCPADataObject; function NextChar : Char; procedure UnGetChar; .... Gruss Reinhard |
Re: Klasse oder Record auf sich selbst?
Danke, das sind ja eine Menge Antworten in der kurzen Zeit :thumb: . Jetzt muss ich mal hier durchspielen, was am besten ist.
|
Re: Klasse oder Record auf sich selbst?
Ich glaube das was du suchst sind Listen:
Delphi-Quellcode:
PMeineListe = ^TMeineListe;
TMeineListe = record Wert1: String; Wert2: Integer; Selbst: PMeineListe; end; |
Re: Klasse oder Record auf sich selbst?
Aber ein Zeiger in der Instanz selber auf die eigene Instanz ist doch total sinnlos. Er wird eher
![]() |
Re: Klasse oder Record auf sich selbst?
Vielleicht liegt das jetzt an meinen Geschmack und die OOP-Fetischisten werden mich jetzt steinigen :wink: , aber ist zur Verwaltung von Bäumen nicht eine Klasse, die einen Zeiger auf den Root kapselt und als Aufbau des Baums Records die aufeinander Zeiger enthalten sinnvoller? Bei der Benutzung von außen (außerhalb dieser Klasse) hat man dann trotzdem nur mit einem schönen Interface der Klasse zu kämpfen, während sie innen organisiert sein kann, wie sie will, und innen erspart man sich den nicht unbeträchlichen Overhead, für jedes Element ein Objekt zu erzeugen.
|
Re: Klasse oder Record auf sich selbst?
Lol .. wer sagt dann das die Instanz auf sich "selbst" zeigt ?! Damit meinte ich nur, dass es vom selben Typ ist! Du könntest genauso Next, Previous hinschreiben .. das ist nukke.
MfG |
Re: Klasse oder Record auf sich selbst?
@Cyf:
Das würde aber nicht dem Ansatz von OOP entsprechen ;-) |
Re: Klasse oder Record auf sich selbst?
Zitat:
Erstens: Ja, kannst du so machen - OOP beinhaltet auch Kapselung ;) Im Grunde kannst du also in der Baum-Klasse machen was du willst, solange ich das Teil problemlos benutzen kann. Allerdings wird es etwas komplizierter sein, die Baumstruktur mit den records zu schreiben da man ja an alle initialisierungen und konsistenzprüfungen denken muss. Btw.: Ich würde gerne mal den "nicht unbeträchlichen Overhead für jedes Element ein Objekt zu erzeugen" sehen - wenn ich richtig informiert bin, stehen die Methoden der Klasse sowiso im Speicher herum. Wenn ein Objekt dann angelegt wird, passiert doch eigenlich nichts weiter, als dass ein Speicherbereich reserviert wird, in den dann der Self-Pointer, die Felder und vll. n paar Typinformationen reinkommen. Kommt dann natürlich noch drauf an, was im Konstruktor passiert. Ist jetzt nicht bös gemeint oder so, aber ich wollte nur mal meinen Senf dazugeben :stupid: (Nein, es ist nicht der mittelscharfe von Develei ^^) |
Re: Klasse oder Record auf sich selbst?
Naja beim erzeugen eines Objektes pasiert schon ein wenig mehr, als beim reservieren von Speicher für einen neuen Record auf dem Heap, bei Objekten müssen ja immer auch Zeiger und Informationen auf die (ja, einmalig, statisch angelegten) RTTI angelegt werden zwecks Methodentabelle etc.
Wenn du im Debugger allein mal den Aufruf von TObject.Create verfolgst, dann kommt in etwa sowas:
Code:
Beim Anfordern von Heap-Speicher für einen Record via New(aPointer) wird das ganze hingegen (solange keine Strings o. ä. beteiligt sind, dann kommt noch ein Initialize hinzu) zu nur einem GetMem. Das mag bei kleinen Datenmengen nicht ins Gewicht Fallen, aber lass es mal große Datenmengen sein, dann macht das prozentual schon etwas aus, auch wenn das praktisch nur dann spürbar sein sollte, wenn diese ständig neu erzeugt werden müssen (z.B. irgendwelche Listen über Objekte die ihren Zustand ändern).
TObject.Create:
00403808 84D2 test dl,dl 0040380A 7408 jz $00403814 0040380C 83C4F0 add esp,-$10 0040380F E830030000 call @ClassCreate 00403814 84D2 test dl,dl 00403816 740F jz $00403827 00403818 E87F030000 call @AfterConstruction 0040381D 648F0500000000 pop dword ptr fs:[$00000000] 00403824 83C40C add esp,$0c 00403827 C3 ret @ClassCreate: 00403B44 52 push edx 00403B45 51 push ecx 00403B46 53 push ebx 00403B47 84D2 test dl,dl 00403B49 7C03 jl $00403b4e 00403B4B FF50F4 call dword ptr [eax-$0c] //<- NewInstance 00403B4E 31D2 xor edx,edx 00403B50 8D4C2410 lea ecx,[esp+$10] 00403B54 648B1A mov ebx,fs:[edx] 00403B57 8919 mov [ecx],ebx 00403B59 896908 mov [ecx+$08],ebp 00403B5C C741046D3B4000 mov [ecx+$04],$00403b6d 00403B63 89410C mov [ecx+$0c],eax 00403B66 64890A mov fs:[edx],ecx 00403B69 5B pop ebx 00403B6A 59 pop ecx 00403B6B 5A pop edx 00403B6C C3 ret TObject.NewInstance: 004037D0 53 push ebx 004037D1 8BD8 mov ebx,eax 004037D3 8BC3 mov eax,ebx 004037D5 E826000000 call TObject.InstanceSize 004037DA E8B1F4FFFF call @GetMem 004037DF 8BD0 mov edx,eax 004037E1 8BC3 mov eax,ebx 004037E3 E85C000000 call TObject.InitInstance 004037E8 5B pop ebx 004037E9 C3 ret 004037EA 8BC0 mov eax,eax TObject.InstanceSize: 00403800 83C0D8 add eax,-$28 00403803 8B00 mov eax,[eax] 00403805 C3 ret 00403806 8BC0 mov eax,eax @GetMem: 00402C90 85C0 test eax,eax 00402C92 7E13 jle $00402ca7 00402C94 FF151C474500 call dword ptr [$0045471c] 00402C9A 85C0 test eax,eax 00402C9C 7402 jz $00402ca0 00402C9E F3C3 rep ret 00402CA0 B001 mov al,$01 00402CA2 E939010000 jmp Error 00402CA7 31C0 xor eax,eax 00402CA9 F3C3 rep ret 00402CAB 90 nop TObject.InitInstance: 00403844 53 push ebx //[...] 00403899 C3 ret @AfterConstruction: 00403B9C 55 push ebp //[...] 00403BC6 83C408 add esp,$08 00403BC9 EB19 jmp $00403be4 00403BCB E930010000 jmp @HandleAnyException 00403BD0 B201 mov dl,$01 00403BD2 8B45FC mov eax,[ebp-$04] 00403BD5 E812000000 call @BeforeDestruction 00403BDA E8DD040000 call @RaiseAgain 00403BDF E82C050000 call @DoneExcept //[...] 00403BE9 C3 ret Folgender Testcode:
Delphi-Quellcode:
mit Zeiger: 240-330ms
procedure TForm1.FormCreate(Sender: TObject);
var Timer: TQPCounter; i: Integer; p: PInteger; begin Timer:= TQPCounter.Create; //eigene Klasse um die Zeit zu messen, unbedeutent for i := 0 to 9999999 do begin New(p); //oder: TObject.Create; über das memory Leak sei mal hinweggesehen, auch das Freigeben dauert beim Objekt länger end; Showmessage(Timer.ClockStr); Timer.Free; end; mit Objekt: 670-690 ms Wie weit das jetzt unter welchen Bedingungen spürbar ist, kann man sich streiten, das ist wahr, bloß der Code zum Verwalten des Baums muss sowieso irgendwo hin, ob jetzt in die Verwaltungsklasse, oder in die Nodes, ist dann egal, also nehm ich die schnellere Variante. :wink: Natürlich gibt es bestimmt auch Situationen, wo die Klasse Sinn macht, etwa bei Kombinationen von verschiedenen Knotenarten, die irgendwie in Beziehung stehen und anders reagieren sollten. [Edit]Zeiten mit Dispose bzw. mit Zuweisung des Objekts auf eine Variable und dann MyObj.Free: leere Schleife: ca. 5,37 ms Zeiger New und Dispose: ca. 150 ms (ja das ist weniger, liegt nicht an Auslastung im Hintergrund o. ä., habs mehrfach verglichen, es ist immer sehr viel weniger, vermute mal, weil nicht immer kleine Mengen Heap angefordert werden, sondern immer die selbe Stelle, die der Memory-Manager noch hält) Objekt Create und Free: ca. 815 ms |
Re: Klasse oder Record auf sich selbst?
Zitat:
Das wären z.B. Koordinaten (x,y) oder komplexe Zahlen (realteil und imaginärteil). Also Dinge, die einerseits sehr kleine Informationsmengen enthalten und andererseits in hohen Stückzahlen von 100000 oder noch mehr gebraucht werden. Dann hat ein Record einen spürbaren Performancevorteil gegenüber einer Klassse. Ein Beispiel wäre ein ![]() Oder Strings - in manchen Progsprachen ist jeder String ein Objekt. Hier hat Delphi ja seinen eigenen Weg gewählt. Wenn Beides aber nicht zutrifft (also geringe Datenmenge und sehr hohe Stückzahl), dann ist der Overhead eines Objekt praktisch nicht spürbar. Dann kann die OOP ihre Trümpfe ausspielen und wer geschickt programmiert brauchst sich um die Leistung keine Sorgen machen. Manchmal erreicht man mit OOP sogar mehr Leistung also ohne. Der Grund dafür ist, dass man mit OOP bestimmte Algorithmen verwenden kann (Objektcache, Nullobjekte, Hashing-Verfahren) die man ohne OOP nicht verwenden könnte ohne das der Sourcecode zu einem unwartbaren Klumpen würde. |
Re: Klasse oder Record auf sich selbst?
Wenn Performance das einzige Kriterium wäre, dann sollte man von OOP die Finger lassen. In der Tat werden viele der fundamentalen Datenstrukturen ohne OOP implementiert. Das liegt aber in erster Linie daran, das man die Vorzüge der OOP hier nicht braucht. Klar kommt noch der Performancefaktor ins Spiel.
Wenn du also eine Klasse für das Speichern von Bäumen schreiben willst, dann verwende ruhig Records für die Baumstruktur, um beim Einfügen von 1 Mio Knoten einen Geschwindigkeitsvorteil von 400ms zu haben (Nebenbei ist ein Baum keine sonderlich schnelle Datenstruktur). Die Schnittstelle wird aber eh eine Klasse sein, da hier die OOP-Vorzüge (Stichwort: Erweiterbarkeit) zum Tragen kommen müssen, und sei es, die Methode des Schlüsselvergleiches (ComapareString, CompareText, etc.) verändern zu können. |
Re: Klasse oder Record auf sich selbst?
Ich habe da es nicht 100000 Datensätze sind, jedenfalls mit OOP gelöst und es klappt super.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:20 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