Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Daten in einer Klassenhierachie ablegen (https://www.delphipraxis.net/79734-daten-einer-klassenhierachie-ablegen.html)

steewan 27. Okt 2006 09:45


Daten in einer Klassenhierachie ablegen
 
Hallo,

ich weiß nicht genau wie ich in Object Pascal an folgendes Problem herangehe. Ich möchte gerne die Struktur eines Autos zum Beispiel in einer Klassenhierachie ablegen. Beispiel:

Auto besteht aus Karosserie, Reifen, Türen, etc. Die Klasse TAuto soll also eine Liste enthalten, welche dann die anderen Objekte TKarosserie, TReifen, TTÜren enthält. Es kann jetzt natürlich vorkommen, dass ein Auto vier oder fünf Türen hat, bzw. die Türen auch wieder aus einer Struktur besteht. Es sollte also ein Objekt in TAuto geben, wo man andere hinterlegen kann:

TAuto
|
|- Objekte : Tweissnichwas

Jetzt soll TAuto.Objekte[1] := Karosserie; TAuto.Objekte[2] := Türen;. In Türen soll dann natürlich auch jede einzelene Tür hinterlegt sein. Also müsste TTüren ebenfalls eine Objektliste enthalten, welche dann immer ein Objekt TTür enthält mit den entsprechenden Eigenschaften. TAuto.Objekte[2] as TTüren.Obejekte[1] := Tür bzw. TTüren.Obejekte[2] := Heckklappe.

Wie bilde ich so etwas in Delphi ab, wie füge ich neue Objekte ein, wie kann ich auf Eigenschaften zugreifen, etc. Gibt es hierzu vielleicht ein gutes Beispiel oder eine Erklärung ??

Besten Dank
Stefan Blankenagel

Jürgen Thomas 27. Okt 2006 10:03

Re: Daten in einer Klassenhierachie ablegen
 
Hallo,
jedes Formular macht das:
  • Form1 ist von einer Klasse TForm abgeleitet und enthält:
  • Edit1 ist von einer Klasse TEdit abgeleitet mit speziellen Eigenschaften
  • Button1 ist von einer Klasse TButton abgeleitet mit speziellen Eigenschaften usw.
Unter NET könntest Du das Verfahren in InitializeComponents() prüfen, wo es für jedes Control einen Create-Befehl gibt und genaue Zuordnungen der Eigenschaften.

Unter Win32 wird es nicht so offensichtlich, aber implizit machen die Verknüpfungen in der Dfm-Datei nichts anderes.

Schau Dir dies einmal genauer an und übertrage es auf Dein Problem. Vielleicht kommst Du damit weiter.

Gruß Jürgen

xZise 27. Okt 2006 12:37

Re: Daten in einer Klassenhierachie ablegen
 
Also ich hätte erstmal einen Autotyp gemacht:
Delphi-Quellcode:
type
  TCar = record
    doors : array of TDoor;
    tires : array of TTire;
  end;
Dann den Türentyp und Reifentyp:

Delphi-Quellcode:
type
  TDoor = record
    width, height : Extended;
    ...
  end;

type
  TTire = record
    radius : Extended;
    tireType : Byte;
    ...
  end;
Du könntest auch statt den Records, Klassen nehmen. Die können dann auch Methoden enthalten und müssen erzeugt/zerstört werden.

steewan 27. Okt 2006 14:38

Re: Daten in einer Klassenhierachie ablegen
 
Hallo,

ja ich hatte es eigentlich mit Klassen vor, da ich dann wirklich dort Methoden einbauen kann. Werde mich noch einmal in diese Richtung damit beschäftigen.

Mit freundlichen Grüßen


Stefan Blankenagel

Hansa 27. Okt 2006 15:46

Re: Daten in einer Klassenhierachie ablegen
 
Zitat:

Zitat von xZise
Also ich hätte erstmal einen Autotyp gemacht:

Ja, da ist OOP gefordert, aber in Deinem Beispiel macht das keinen Sinn, weil es eben kein OOP ist ! :mrgreen:

So würde es schon anders aussehen :

Delphi-Quellcode:
type
  TCar = class
    Breite, Höhe, Länge : real;
    AnzahlTueren,
    AnzahlFenster : integer;
  end;

  TPkw = class (TCar)
    Schiebedach : boolean;
  end;
Der Pkw hat dadurch schon direkt eingebaute Türen, Fenster usw. Das TCar hat die noch nicht. Beispiele in dieser Richtung finden sich auch zu Dutzenden im Internet. Man muß sie eben mal lesen und umsetzen. :zwinker:

Edit : Delphi-Tag falsch gesetzt und gleich der nächste Tip : Methoden lassen sich da auch gut einbauen. Trotzdem würde ich zunächst mal die Datenstrukturen richtig aufbauen.

steewan 28. Okt 2006 08:55

Re: Daten in einer Klassenhierachie ablegen
 
Für die Programmentwicklung ist eine genaue Planung der Datenstruktur sehr wichtig. Deshalb mac h ich mir ja die Gedanken.

Ich habe mir jetzt folgende Datenstruktur gebastelt:

Delphi-Quellcode:
    TLeuchte = class
     private
       FZielort : string;
       FAdresse : integer;
     public
       constructor create;
       destructor Destroy; override;
       property Zielort : string read FZielort write FZielort;
       property Adresse : integer read FAdresse write FAdresse;
     end;

     TStromkreis = class
     private
       FAdresse : integer;
       FLeuchten : Array of TLeuchte;

       function GetLeuchte(index:integer):TLeuchte;
     public
       constructor create;
       destructor destroy; override;

       property Leuchte[index:integer]:TLeuchte read GetLeuchte; default;

       property Adresse : integer read FAdresse write FAdresse;
       function get_Anzahl_Leuchten : integer;

       procedure Add_Leuchte(vAdresse : integer; vZielort: string);
       procedure clear_Leuchten;
     end;

     TEinschub = class
     private
       FStromkreise : Array of TStromkreis;
       FAdresse : integer;
       FTyp : integer;

       function GetStromkreis(index:integer):TStromkreis;
     public
       constructor create;
       destructor destroy; override;

       property typ : integer read FTyp write FTyp;
       property Stromkreis[index:integer]:TStromkreis read GetStromkreis; default;
       property Adresse : integer read FAdresse write FAdresse;

       function get_Anzahl_Stromkreise : integer;

       procedure Add_Stromkreis(vAdresse:integer);
     end;

     TGeraet = class
     private
       FZielort : string;
       FAdresse : integer;
       FTyp    : integer;
       FEinschuebe : Array of TEinschub;

       function getEinschub(index:integer):TEinschub;
     public

       constructor create;
       destructor destroy; override;

       property Einschub[index:integer]: TEinschub read getEinschub; default;
       property Zielort : string read FZielort write FZielort;
       property Typ : integer read FTyp write FTyp;
       property Adresse : integer read FAdresse write FAdresse;

       function get_Anzahl_Einschuebe : integer;

       procedure Add_Einschub(vTyp : integer; vAdresse: integer);
     end;
Die Prozedur zum einfügen von Daten sind diese:

Delphi-Quellcode:
procedure TGeraet.Add_Einschub(vTyp : integer; vAdresse : integer);
var idx : integer;
    vEinschub : TEinschub;
begin
  idx := get_Anzahl_Einschuebe;
  SetLength(FEinschuebe, idx + 1);

  vEinschub := TEinschub.create;
  FEinschuebe[idx] := vEinschub;
  vEinschub.Free;

  FEinschuebe[idx].Typ := vTyp;
  FEinschuebe[idx].Adresse := vAdresse;
end;

procedure TEinschub.Add_Stromkreis(vAdresse : integer);
var idx : integer;
    vStromkreis : TStromkreis;
begin
  idx := get_Anzahl_Stromkreise;
  SetLength(FStromkreise, idx + 1);

  vStromkreis := TStromkreis.create;
  FStromkreise[idx] := vStromkreis;

  FStromkreise[idx].Adresse := vAdresse;
  vStromkreis.Free;
end;

procedure TStromkreis.Add_Leuchte(vAdresse : integer; vZielort: string);
var idx : integer;
    vLeuchte : TLeuchte;
begin
  idx := get_Anzahl_Leuchten;
  SetLength(FLeuchten, idx + 1);

  vLeuchte := TLeuchte.create;
  FLeuchten[idx] := vLeuchte;
  vLeuchte.Free;

  FLeuchten[idx].Adresse := vAdresse;
  FLeuchten[idx].Zielort := vZielort;
end;
Wenn nun die Struktur mit Daten gefüllt werden sollen, kommt eine Zugriffsverletzung:

Delphi-Quellcode:
  FGeraet := TGeraet.Create;
  FGeraet.Add_Einschub(JSUSV23, 1);
  FGeraet.Einschub[0].Add_Stromkreis(1);
  FGeraet.Einschub[0].Add_Stromkreis(2);
  FGeraet.Einschub[0].Stromkreis[0].Add_Leuchte(1, 'Toilette Herren'); //Hier kommt eine Zugriffsverletzung
  FGeraet.Einschub[0].Stromkreis[0].Add_Leuchte(2, 'Toilette Damen');
  FGeraet.Einschub[0].Stromkreis[0].Add_Leuchte(3, 'Eingang');
  FGeraet.Einschub[0].Stromkreis[0].Add_Leuchte(4, 'Ausgang');
  FGeraet.Einschub[0].Stromkreis[0].Add_Leuchte(5, 'Irgendein Text');
  FGeraet.Einschub[0].Stromkreis[1].Add_Leuchte(6, 'Eine 6. Leuchte');
  FGeraet.Einschub[0].Stromkreis[1].Add_Leuchte(5, 'Toilette Herren');
  FGeraet.Einschub[0].Stromkreis[1].Add_Leuchte(4, 'Toilette Damen');
  FGeraet.Einschub[0].Stromkreis[1].Add_Leuchte(3, 'Eingang');
  FGeraet.Einschub[0].Stromkreis[1].Add_Leuchte(2, 'Ausgang');
  FGeraet.Einschub[0].Stromkreis[1].Add_Leuchte(1, 'Irgendein Text');
Ich dachte erst, es liegt daran, dass ich schon zwei Stromkreise eingefügt habe und jetzt eine Leuchte in Stromkreis 1 einfüge, wodurch aber Speicherplatz im Bereich zwischen Stromkreis 1 und Stromkreis 2 reserviert werden muss. Auch nach Auskommentierung von Add_Stromkreis(2) erscheint in der folgenden Zeile die Zugriffsverletzung.

Gruß
Stefan Blankenagel

xZise 28. Okt 2006 10:42

Re: Daten in einer Klassenhierachie ablegen
 
Zitat:

Zitat von steewan
Delphi-Quellcode:
procedure TGeraet.Add_Einschub(vTyp : integer; vAdresse : integer);
var idx : integer;
    vEinschub : TEinschub;
begin
  idx := get_Anzahl_Einschuebe;
  SetLength(FEinschuebe, idx + 1);

  vEinschub := TEinschub.create;
  FEinschuebe[idx] := vEinschub;
  vEinschub.Free;

  FEinschuebe[idx].Typ := vTyp;
  FEinschuebe[idx].Adresse := vAdresse;
end;

procedure TEinschub.Add_Stromkreis(vAdresse : integer);
var idx : integer;
    vStromkreis : TStromkreis;
begin
  idx := get_Anzahl_Stromkreise;
  SetLength(FStromkreise, idx + 1);

  vStromkreis := TStromkreis.create;
  FStromkreise[idx] := vStromkreis;

  FStromkreise[idx].Adresse := vAdresse;
  vStromkreis.Free;
end;

procedure TStromkreis.Add_Leuchte(vAdresse : integer; vZielort: string);
var idx : integer;
    vLeuchte : TLeuchte;
begin
  idx := get_Anzahl_Leuchten;
  SetLength(FLeuchten, idx + 1);

  vLeuchte := TLeuchte.create;
  FLeuchten[idx] := vLeuchte;
  vLeuchte.Free;

  FLeuchten[idx].Adresse := vAdresse;
  FLeuchten[idx].Zielort := vZielort;
end;

Dast geht auch anders:

Delphi-Quellcode:
{ * Variante 1 = Direkte Instanzierung + with * }

procedure TGeraet.Add_Einschub(vTyp : integer; vAdresse : integer);
var idx : integer;
begin
  idx := get_Anzahl_Einschuebe;
  SetLength(FEinschuebe, idx + 1);

  with FEinschuebe[idx] := TEinschub.create do begin
    Typ := vTyp;
    Adresse := vAdresse;
  end;
end;

{ * Variante 2 = direkte Instanzierung * }

procedure TEinschub.Add_Stromkreis(vAdresse : integer);
var idx : integer;
begin
  idx := get_Anzahl_Stromkreise;
  SetLength(FStromkreise, idx + 1);

  FStromkreise[idx] := TStromkreis.create;
  FStromkreise[idx].Adresse := vAdresse;
end;

{ * Variante 3 = direkte Instanzierung + Verzicht, auf eigene Methoden * }

procedure TStromkreis.Add_Leuchte(vAdresse : integer; vZielort: string);
begin
  SetLength(FLeuchten, Length(FLeuchten) + 1);

  FLeuchten[High(FLeuchten)] := TLeuchte.create;
  FLeuchten[High(FLeuchten)].Adresse := vAdresse;
  FLeuchten[High(FLeuchten)].Zielort := vZielort;

// Ich bin mir nicht sicher, ob es hier mit with effektiver ist, da nur einmal die "High()" - Methode aufgerufen werden muss (siehe Variante 1)
end;
Zu deinem Problem: Debug mal in "Add_Leuchte" und sag uns, wo dort der Fehler auftritt... Vielleicht ist "get_Anzahl_Leuchten" "defekt" :D

Hansa 28. Okt 2006 13:44

Re: Daten in einer Klassenhierachie ablegen
 
Ist der Titel des Themas eventuell gar nicht mehr gültig ? Ich sehe jedenfalls nur eine Aneinanderreihung verschiedener Typen, die nichts miteinander zu tun haben. Da ist nichts zu sehen in Richtung "Klassenhierarchie". :shock: Deshalb ist das verwendete override in den Deklarationen auch überflüssig. Glaube zwar nicht, daß das einen bemerkbaren Fehler verursacht, aber es ist trotzdem einer. Dann noch als Beispiel das FAdresse. Wieso wird das überall neu deklariert ? Warum nicht tatsächlich eine Hierarchie, die damit beginnt alles gemeinsame erst mal in eine Basisklasse zu packen und die dann zu vererben. Dabei wird bei den Nachfolgern nur noch das neu deklariert, was auch tatsächlich hinzu kommt. Das gilt nicht nur für Daten, sondern auch für eventuell notwendige neue Methoden.

Ich gehe jetzt mal von dem Auto weg. Geometrische Figuren eignen sich besser. Fangen wir beim Punkt an. Was braucht der ? Eigentlich nur Koordinaten. Na gut er kriegt noch eine Farbe :

Delphi-Quellcode:
TPunkt = class
  x,y : integer;
  Farbe : TColor;
end;
Dann kommt der Kreis. Der hat auch einen Mittelpunkt und eine Farbe. Es kommt hinzu : ein Radius und ich muß ihn zeichnen, also eine durch dem Mittelpunkt und den Radius bestimmte Fläche ausfüllen. Der Punkt hat aber bereits einiges, was man für den Kreis braucht und der sieht deshalb so aus :

Delphi-Quellcode:
TKreis = class (TPunkt)
  Radius : integer;
  protected
     procedure Zeichnen; virtual;
end;
Mehr braucht man nicht, das was in der Deklaration nicht zu sehen ist, das liefert schon der Punkt. Jetzt gehen mir langsam die Ideen aus. Ellipse ist mir zu schwer. :mrgreen: Aber wie wäre es noch mit einem berechneten Kreis ? Der soll genauso angezeigt werden, hat auch einen Mittelpunkt und einen Radius. Zusätzlich will ich aber die Fläche und den Umfang wissen:

Delphi-Quellcode:
TBerechneterKreis = class (TKreis)
  Flaeche,
  Umfang : real;
  protected
    procedure BerechneFlaeche; virtual;
    procedure BerechneUmfang; virtual;
end;
Der Rest steckt bereits im Kreis (procedure Zeichnen) oder sogar schon im Punkt (x,y,Farbe). Es kommt eben noch was hinzu. Dann noch ein Quadrat und es stellt sich die Frage, wo man da ansetzen soll. Es hat keinen Radius, sondern sagen wir eine Kantenlaenge. Anders gezeichnet werden muß es auch. Wegen des erwähnten "override" benutze ich aber den Kreis und ignoriere den Radius :

Delphi-Quellcode:
TQuadrat = class (TKreis)
  KantenLaenge : integer;
  protected
     procedure Zeichnen; override;
end;
Da ich vom Kreis her komme, brauche ich ja eine komplett andere Zeichenmethode. Deshalb wird die hier neu deklariert und per override wird die alte vollkommen ignoriert. Bräuchte ich tatsächlich solche Figuren, würde ich wohl nach dem TPunkt eine Weggabelung in der Hierarchie machen. Kreise, Ellipsen usw. und das andere wäre Quadrat, Rechteck, wie heißt noch das schiefe Quadrat ? :gruebel: Da kämen dann auch Winkel ins Spiel usw. So, hoffe mal, daß das hier nicht nur was für Sakura ist. :mrgreen:

steewan 1. Nov 2006 21:08

Re: Daten in einer Klassenhierachie ablegen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,

vielleicht kann mir noch einmal jemand helfen. Beiliegender Programmcode erzeugt in folgender Prozedur eine Zugriffsverletzung:

Delphi-Quellcode:
procedure TStromkreis.Add_Leuchte(vAdresse : integer; vZielort: string);
var idx : integer;
vLeuchte : TLeuchte;
begin
idx := get_Anzahl_Leuchten + 1;
SetLength(FLeuchten, idx + 1);
vLeuchte := TLeuchte.create;
FLeuchten[idx] := vLeuchte;

FLeuchten[idx].Adresse := vAdresse;
FLeuchten[idx].Zielort := vZielort;
end;
Und ich habe leider keine Ahnung, warum dies so ist. Anscheinend existiert etwas nicht mehr die Länge von der Funktion get_Anzahl_Leuchten ist auf einmal ziemlich groß.

mfg
Stefan

mkinzler 1. Nov 2006 21:10

Re: Daten in einer Klassenhierachie ablegen
 
Delphi-Quellcode:
FLeuchten[idx-1] := vLeuchte;


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:48 Uhr.
Seite 1 von 2  1 2      

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