Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Eigenen Typ in Klasse (https://www.delphipraxis.net/73299-eigenen-typ-klasse.html)

zer00 15. Jul 2006 12:32


Eigenen Typ in Klasse
 
Hi all

Ich möchte in einer eigenen Klasse einen Record-Typ in einem Dynamischen Array speichern, nun sollte aber der Record-Typ auch von aussen sichtbar sein.
Der User der Klasse soll eine neue Variable des Record-Typs deklarieren können und diese dann an eine Methode der Klasse übergeben.
z.B. so:

Delphi-Quellcode:
var Foo: TRecord;
Klasse.Add(foo);
Leider habe ich keine Ahnung wie ich das in meiner Klasse implementieren muss.

grz zer00

arbu man 15. Jul 2006 12:42

Re: Eigenen Typ in Klasse
 
Deine add proc könnte so aussehen:
Delphi-Quellcode:
procedure tetc.add(foo: Tdeinrecord);
begin
  setlength(derarray, length(derarray)+1)
  derarray[length(derarray)]:= foo;
end;
(aus dem kopf)

r2c2 15. Jul 2006 12:44

Re: Eigenen Typ in Klasse
 
So vielleicht:
Delphi-Quellcode:
TRecord = record
  Data: string;
  Data2: Integer;
end;

TTest = class(TObject)
private
  FData: TList;
public
  constructor Create;
  destructor Detroy; override;
  property: Data: TList read FData write FData;
  procedure Add(Data: TRecord);
end;

constructor TTest.Create;
begin
  inherited Create;
  FList := TList.Create;
end;

destructor TTest.Destroy;
begin
  FList.Free;
  inherited Destroy;
end;

procedure TTest.Add(Data: TRecord);
begin
  FData.Add(@Data);
end;
Quellcode ungetestet. Nur so runtergetippt. Auch die Speicherverwaltung der Records(new, dispose) fehlt noch. Sollte aber so ne Idee von dem geben, wie das aussehen könnte. BTW: Warum willst du eigentlich n Record nehmen? Warum nicht auch ne Klasse. Dann könntest du dir die Speicherverwaltung nämlich schenken(TObjectList, ggf. + Template).

mfg

Christian

chaoslion 15. Jul 2006 12:46

Re: Eigenen Typ in Klasse
 
mal ne Frage, ist es nicht "sicherer", alle Daten eines Records exakt zu übertragen, also

Delphi-Quellcode:
procedure add( foo: trec );
begin
 self.arrayoftrec[..].t1 := foo.t1;
 self.arrayoftrec.t2 := foo.t2;
end;
anstatt zu sagen:
Delphi-Quellcode:
...
 self.arrayoftrec[...] := foo;
...
??

r2c2 15. Jul 2006 12:55

Re: Eigenen Typ in Klasse
 
Zitat:

Zitat von chaoslion
mal ne Frage, ist es nicht "sicherer", alle Daten eines Records exakt zu übertragen?

Warum? :gruebel: Wenn du die selbe Record-Deklaration hast und alles andere wäre...ähm...komisch, dann is die andere Variante nur mehr Schreibarbeit und muss dazu noch jedes Mal, wenn sich der Record-Typ ändert, neu angepasst werden...

mfg

Christian

Christian Seehase 15. Jul 2006 12:59

Re: Eigenen Typ in Klasse
 
Moin arbu man,

wobei man aus Performance Gründen nicht gerade immer um 1 erhöhen sollte.
Erst einmal auf die zu erwartende Grösse setzen, und beim Hinzufügen prüfen, ob noch Platz ist, dann ggf. um einen bestimmten Wert erhöhen.
Beim Vergrössern mittels SetLength wird jedesmal ein neues Array angelegt, und der Inhalt des alten dort hineinkopiert.

Hawkeye219 15. Jul 2006 13:05

Re: Eigenen Typ in Klasse
 
Auf jeden Fall sollte man nur die gültigen Elemente des Arrays benutzen:

Delphi-Quellcode:
procedure tetc.add(foo: Tdeinrecord);
begin
  setlength(derarray, length(derarray)+1)
  derarray[High(derarray)]:= foo; // <-- High() statt Length()
end;
Gruß Hawkeye

Der_Unwissende 15. Jul 2006 20:55

Re: Eigenen Typ in Klasse
 
Zitat:

Zitat von Hawkeye219
Auf jeden Fall sollte man nur die gültigen Elemente des Arrays benutzen:

Delphi-Quellcode:
procedure tetc.add(foo: Tdeinrecord);
begin
  setlength(derarray, length(derarray)+1)
  derarray[High(derarray)]:= foo; // <-- High() statt Length()
end;

Hi,
noch viel besser ist es, hier einfach gar kein Array zu verwenden. Ein Array ist nun mal eine recht statische Struktur und
Delphi-Quellcode:
setLength(Array, length(Array) + 1);
ist nicht wirklich empfehlenswert (kostet unnötig Zeit und wird vom Speichermanager nicht unbedingt optimal gelöst). Viel besser ist es, wenn du einfach eine TList verwendest, die ist genau dafür gedacht. An sich kannst du deine Records viel schöner als Pointer auf den Record übergeben (ist schneller) und diesen Pointer kannst du dann in deiner TList speichern. Wenn du lesend auf das Array zugreifst, dann kannst du hier ganz einfach eine Methode anlegen, die die TList in ein Array umwandelt. Schreibend kannst du auch Wahlfrei auf die TList zugreifen.

Gruß Der Unwissende

r2c2 15. Jul 2006 21:16

Re: Eigenen Typ in Klasse
 
Zitat:

Zitat von Der_Unwissende
Viel besser ist es, wenn du einfach eine TList verwendest, die ist genau dafür gedacht. An sich kannst du deine Records viel schöner als Pointer auf den Record übergeben (ist schneller) und diesen Pointer kannst du dann in deiner TList speichern. Wenn du lesend auf das Array zugreifst, dann kannst du hier ganz einfach eine Methode anlegen, die die TList in ein Array umwandelt. Schreibend kannst du auch Wahlfrei auf die TList zugreifen.

Den Vorschlag kenn ich doch irgendwo her... :stupid: :mrgreen:

mfg

Christian

zer00 15. Jul 2006 23:16

Re: Eigenen Typ in Klasse
 
Danke für die vielen Antworten!
Sehe ich das richtig, dass ich mein Problem am besten mit einer Verketteten Liste löse.
Da ich aber noch nie viel mit Pointern gearbeitet habe werde ich sicher noch ein paar Fragen an euch haben.
Bitte habt ein bisschen Geduld. ;)

grz zer00

Elvis 15. Jul 2006 23:24

Re: Eigenen Typ in Klasse
 
Zitat:

Zitat von zer00
Danke für die vielen Antworten!
Sehe ich das richtig, dass ich mein Problem am besten mit einer Verketteten Liste löse.

Wenn du < 20 Elemente hast, vielleicht. Aber wahrscheinlich nicht. Die Zeiten ändern sich, mit den flachen Adressräumen wurden linked Lists immer unbedeutender. Ein array-basierter Container wie die TList-Ableitungen wäre schon mehr als OK. ;)
Du fährst aber definitiv besser wenn du deine Daten als Instanzen von Klassen abbildest. Records/Structs haben ihre Berechtigungen IMHO nur, wenn man mit einem Speicherbereich fixer Größe arbeiten muss, der in fest vorgechriebene Felder unterteilt wird. Zum Beispiel für API calls.
Eine Instanz einer Klasse kostet dich eigentlich nur ihren VMT-Pointer als Overhead, dafür gewinnst du neben Polymorphie noch einiges an Unterstützung des Compilers. ;)

Der_Unwissende 16. Jul 2006 07:29

Re: Eigenen Typ in Klasse
 
Zitat:

Zitat von r2c2
Den Vorschlag kenn ich doch irgendwo her... :stupid: :mrgreen:

mfg

Christian

Ups, sorry den Beitrag (also den Code) gar nicht näher angeschaut, peinlich.

zer00 22. Jul 2006 09:20

Re: Eigenen Typ in Klasse
 
Zitat:

Zitat von Elvis
Wenn du < 20 Elemente hast, vielleicht. Aber wahrscheinlich nicht. Die Zeiten ändern sich, mit den flachen Adressräumen wurden linked Lists immer unbedeutender. Ein array-basierter Container wie die TList-Ableitungen wäre schon mehr als OK. ;)
Du fährst aber definitiv besser wenn du deine Daten als Instanzen von Klassen abbildest. Records/Structs haben ihre Berechtigungen IMHO nur, wenn man mit einem Speicherbereich fixer Größe arbeiten muss, der in fest vorgechriebene Felder unterteilt wird. Zum Beispiel für API calls.
Eine Instanz einer Klasse kostet dich eigentlich nur ihren VMT-Pointer als Overhead, dafür gewinnst du neben Polymorphie noch einiges an Unterstützung des Compilers. ;)

So ich habe versucht den Tip mit der Instanz der Klasse umzusetzen.
Ich hoffe ich habe das in etwa richtig gemacht.

Code Form1

Delphi-Quellcode:
implementation
uses Termin;
{$R *.dfm}

var Liste: TList;
    index: integer;

procedure TForm1.NewItem(name, nr: String);
begin
  Liste.Add(TTermin.Create(name,nr));
  Label2.Caption:= IntToStr(index);
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  Liste:= TList.Create;
  index:= 0;
end;



procedure TForm1.Button1Click(Sender: TObject);
var name, nr: string;
begin
  name:= Edit1.Text;
  nr:= Edit2.Text;
  NewItem(name,nr);
end;


procedure TForm1.Button2Click(Sender: TObject);
begin
  Edit1.Text:= TTermin(Liste[index]).name;
  Edit2.Text:= TTermin(Liste[index]).nr;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  Edit1.Clear;
  Edit2.Clear;
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
  if(index < Liste.Count -1) then
    inc(index);
    Label2.Caption:= IntToStr(index);
    self.Button2.Click;
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  if(index > 0) then
    dec(index);
    Label2.Caption:= IntToStr(index);
    Self.Button2.Click;
end;

Code der Klasse

Delphi-Quellcode:
unit Termin;

interface


type
  TTermin = class(TObject)
  private
    { Private-Deklarationen }
    FName: String;
    FNr: String;

  public
    { Public-Deklarationen }
    property Name: String read FName write FName;
    property nr: String read FNr write FNr;
    Constructor Create(Name, nr: String);
  end;

implementation

Constructor TTermin.Create(Name, nr: String);
begin
  inherited Create;
  FName:= Name;
  FNr:= nr;
end;

end.
Jetzt ist mir einfach nicht ganz klar wie ich die Instanzen wieder freigebe, reicht es wenn ich alle Objects in meiner Liste mit Free freigebe und anschliessend die Liste selbst mit Free freigebe?

grz zer00

Hawkeye219 22. Jul 2006 10:25

Re: Eigenen Typ in Klasse
 
Hallo zer00,

wenn du statt einer TList eine Delphi-Referenz durchsuchenTObjectList aus der Unit Contnrs verwendest, übernimmt diese die Freigabe der enthaltenen Elemente. Vielleicht wäre es noch besser, in der Unit 'Termin' eine abgeleitete Klasse zu definieren:

Delphi-Quellcode:
// uses Contnrs;

type
  TTerminListe = class (TObjectList)
  private
    function GetTermin (aIndex: Integer): TTermin;
  public
    function NeuerTermin (const aName, aNr: string): TTermin;
    property Termin [aIndex: Integer]: TTermin
      read GetTermin; Default;
  end;

function TTerminListe.GetTermin (aIndex: Integer): TTermin;
begin
  Result := TTermin(Items[aIndex]);
end;

function TTerminListe.NeuerTermin (const aName, aNr: string): TTermin;
begin
  Result := TTermin.Create(aName, aNr);
  Add(Result);
end;
Wenn du dieser Klasse weitere Methoden spendierst (z.B. LoescheTermin), dann kannst du die gesamte Verwaltung der Termine dort kapseln.
Die Verwendung in deinem Programm könnte etwas so aussehen:

Delphi-Quellcode:
var Liste : TTerminListe;

procedure TForm1.Button2Click(Sender: TObject);
begin
  Edit1.Text := Liste[index].Name;
  Edit2.Text := Liste[index].nr;
end;
Noch eine Bemerkung zu den Prozeduren 'Button4Click' und 'Button5Click': du weißt hoffentlich, daß immer nur eine Anweisung von einem IF abhängt. Wenn alle drei Anweisungen nur im True-Fall ausgeführt werden sollen, dann mußt du sie mit BEGIN..END klammern:

Delphi-Quellcode:
if(index > 0) then
begin
  dec(index);
  Label2.Caption:= IntToStr(index);
  Self.Button2.Click;
end;
Du solltest den Controls auf deinem Formular übrigens aussagekräftigere Namen geben, dann muß man nicht raten, was die einzelnen Routinen bewirken. :wink:

Gruß Hawkeye

zer00 22. Jul 2006 10:46

Re: Eigenen Typ in Klasse
 
Zitat:

Zitat von Hawkeye219
Hallo zer00,

wenn du statt einer TList eine Delphi-Referenz durchsuchenTObjectList aus der Unit Contnrs verwendest, übernimmt diese die Freigabe der enthaltenen Elemente. Vielleicht wäre es noch besser, in der Unit 'Termin' eine abgeleitete Klasse zu definieren:


Du solltest den Controls auf deinem Formular übrigens aussagekräftigere Namen geben, dann muß man nicht raten, was die einzelnen Routinen bewirken. :wink:

Gruß Hawkeye

Danke für deine Antwort.
Ich werde versuchen deine Tips umzusetzen.
Ja ich weiss, dass nur eine Anweisung von IF abhängt.
Ich werde versuchen meine Controls besser zu benennen. ;)

Und noch einmal vielen Dank!
grz zer00

zer00 9. Aug 2006 20:16

Re: Eigenen Typ in Klasse
 
@ Hawkeye

Ich habe da noch ne Frage bezüglich der ObjectList, ich muss aus zwei Forms auf die Liste zugreiffen, wie mache ich das?

grz zer00

r2c2 9. Aug 2006 20:37

Re: Eigenen Typ in Klasse
 
Deklarier die ObjectList public oder nimm zur Not ne globale Deklaration(nicht so schön).

mfg

Christian

P.S.: ggf. solltest du dazu n neues Thema aufmachen. Zugegeben grenzwertig, aber man könnte das auch als neue Frage auffassen...

Chewie 9. Aug 2006 21:34

Re: Eigenen Typ in Klasse
 
Zitat:

Zitat von zer00
ne Frage bezüglich der ObjectList, ich muss aus zwei Forms auf die Liste zugreiffen, wie mache ich das?

Du übergibst den Forms einfach eine Referenz auf die Objectlist, so sparst du dir unsaubere und unübersichtliche globale Deklarationen.

zer00 9. Aug 2006 23:08

Re: Eigenen Typ in Klasse
 
Danke für die Antworten.
Jetzt habe ich es so gelöst.
Ich habe eine Klasse TKalender, die für die Anzeige von Tages-, Wochen-, Monatsansicht so wie für die auslösung von Terminen und das verwalten der ObjectList verantwortlich ist.

Jetzt habe ich in Form1(Mainform) eine Objectvarible von Typ TKalender erzeugt.
Wenn ich jetzt aus Form2 in die ObjectList schreiben will rufe ich Form1.Kalender.Liste.NeuerTermin(); auf.
Ist das in etwa richtig? (Bitte seid ein bisschen geduldig mit mir ;) )

grz zer00


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:41 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz