Untergeordnete Klassen

Aloxen
Beiträge: 58
Registriert: Di 31. Mai 2022, 17:40

Untergeordnete Klassen

Beitrag von Aloxen »

Hi ich kenne mich noch nicht gut mit Klassen aus, daher eine wahrscheinlich einfachere Frage:
Ich habe eine Objektliste, in der "Blocks" Speichern möchte. Im Programm können dann beliebig viele Blöcke hinzugefügt werden. Jetzt möchte ich aber unterschiedliche Würfelarten haben. Also es soll bspw. Einen Block "Bricks" und einen Block "Holz" geben. Es unterscheiden sich jeweil die Textur und die Oberflächenbeschaffenheit. Um es Strukturierter zu machen und dabei etwas über Klassen zu lernen wollte ich wie eine Art Unterklasse für jede Blockart nehmen. Gleichzeitig sollen alle Blöcke (egal welche Art) in einer Objektliste gespeichert werden. Sprich:

Code: Alles auswählen

type
  TBlockList = class(specialize TFPGObjectList<TBlock>)
    public
  end;
 var
  ABlockList: TblockList;
Meine Fragen:

1. Wie erstelle ich die Unterklassen, die beschrieben um welche Art des Blocks es sich handelt
2. Wie würde ich dann einen Block der Art "Holz" zur Blockliste hinzufügenhinzufügen

Benutzeravatar
theo
Beiträge: 10497
Registriert: Mo 11. Sep 2006, 19:01

Re: Untergeordnete Klassen

Beitrag von theo »

Aloxen hat geschrieben:
Di 8. Nov 2022, 20:18
1. Wie erstelle ich die Unterklassen, die beschrieben um welche Art des Blocks es sich handelt

Code: Alles auswählen

  THolz = class (TBlock)
...
  end;
Aloxen hat geschrieben:
Di 8. Nov 2022, 20:18
2. Wie würde ich dann einen Block der Art "Holz" zur Blockliste hinzufügenhinzufügen

Code: Alles auswählen

ABlockList.Add(AHolz) 
//oder 
ABlockList.Add(THolz.Create());
Z.B. https://de.wikibooks.org/wiki/Programmi ... _Vererbung
https://www.delphi-treff.de/tutorials/o ... ashkurs/8/

PascalDragon
Beiträge: 830
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: Untergeordnete Klassen

Beitrag von PascalDragon »

Aloxen hat geschrieben:
Di 8. Nov 2022, 20:18

Code: Alles auswählen

type
  TBlockList = class(specialize TFPGObjectList<TBlock>)
    public
  end;
 var
  ABlockList: TblockList;
Als kleine Anmerkung am Rande: wenn du keine Eigenschaften oder Methoden zur TBlockList hinzufügen möchtest reicht es übrigens TBlockList = specialize TFPGObjectList<TBlock> zu schreiben.
FPC Compiler Entwickler

Aloxen
Beiträge: 58
Registriert: Di 31. Mai 2022, 17:40

Re: Untergeordnete Klassen

Beitrag von Aloxen »

Vielen Dank

Aloxen
Beiträge: 58
Registriert: Di 31. Mai 2022, 17:40

Re: Untergeordnete Klassen

Beitrag von Aloxen »

Eine letzte Frage. Muss ich noch etwas beachten wenn ich auf Werte aus der TBlock Klasse zugreife? Also wenn ich im Constructor von THolz bspw auf die Position zugreifen möchte, welche in TBlock hinterlegt ist, was muss ich da schreiben? Die Position ist in yprivate

Benutzeravatar
theo
Beiträge: 10497
Registriert: Mo 11. Sep 2006, 19:01

Re: Untergeordnete Klassen

Beitrag von theo »

Verstehe die Frage nicht so ganz und weiss auch nicht, was deine "Position" genau ist.
Normalerweise geht das so, wie wenn es in der abgeleiteten Klasse deklariert wäre.
Vielleicht "Position" in der Elternklasse statt in "private" in "protected" ablegen.

Wenn du Methoden überschreibst, kannst du diejenige der Elternklasse mit "inherited" aufrufen.
https://wiki.freepascal.org/Inherited

Aloxen
Beiträge: 58
Registriert: Di 31. Mai 2022, 17:40

Re: Untergeordnete Klassen

Beitrag von Aloxen »

Code: Alles auswählen

Type
  TBlock=class
     private
       F_obj:TMatrix;
     public
       property T_obj read F_obj write F_obj;
 Type
   THolz = class(TBlock)
      Private
        F_Texture:~keine Ahnung~;
        F_material:Tvector4f;
      Public
        constructor place(x,y,z:real);

Code: Alles auswählen

Constructor THolz.place(x,y,z:real);
Begin
   Inherited;
   T_obj.translate(x,y,z)
   F_texture:=….;
   ….
End
Wenn ich einen Block erstelle soll das über bspw THolz.place() gehen. Man gibt dabei die xyz Koordinate an, an der der Block erstellt werden soll. Die Aktuelle Position eines Körpers ist in der F_obj gespeichert. Durch .Translste verschiebt man die Matrix und somit den Block.

Fragen:
1. Kann ich die obj in TBlock stehen lassen, oder wird, wenn ich die Obj verändere die obj für alle Unterklassen geändert. Wenn ich jetzt bspw einen Block der Klasse THolz mit THolz.place(2,1,0) erstelle und dann einen nächsten von der Klasse T_Brick.place(-2,1,0) erstelle, ist die Obj dann für beide unabhängig oder verändere ich, wenn ich die obj verändere die Position beider Würfel?(Ich dachte mir es wäre übersichtlicher wenn ich Eigenschaften, die alle Blöcke haben müssen in TBlock zu packen. Lohnt es sich überhaupt die obj in T_Block zu packen? )
2. Habe ich im Constructor die obj richtig angesprochen oder muss sowas wie Self.t_obj.translate da hin?
3.Die Texture ist eine XML Datei. Wie würde der Variablentyp dafür heißen?

Ich hoffe es ist jetzt verständlichlicher. Vielen Dank für die Hilfe schon mal

Benutzeravatar
theo
Beiträge: 10497
Registriert: Mo 11. Sep 2006, 19:01

Re: Untergeordnete Klassen

Beitrag von theo »

1. Du solltest den Unterschied zwischen Klasse und Objekt verstehen.
Eine Klasse ist nur ein Schnittmuster oder eine Bauanleitung. Eine Klasse hält noch keine Daten.
Erst das Objekt kann Daten halten.

Code: Alles auswählen

MeinObjekt::=TMeineKlasse.Create();
MeinObjekt hat Platz reserviert für seine eigenen Daten. Diese teilt es mit niemandem, egal ob vererbt oder nicht.
Also veränderst du in einem anderen Objekt nichts.

2. Nenne den Konstruktor immer Create, das ist so üblich und verhindert Verwirrung.
Ebenso ist der Name für das Property ungünstig gewählt. Mit "T" fangen sonst immer Typen an.

Mach es so:

Code: Alles auswählen

Type

  { TBlock }

  TBlock = class
  private
    fMatrix: TMatrix;
  public
    property Matrix: TMatrix read fMatrix write fMatrix;
  end;

  { THolz }
  
  THolz = class(TBlock)
  private
    fTexture: string;
    fMaterial:Tvector4f;
  public
    constructor Create(x, y, z: real);
  end;   
3. Das kann man so nicht sagen. Was soll das genau sein?
Ein Dateipfad? Die Daten der XML Datei als String, oder als zugreifbares TXMLDocument?

Und probier doch einfach mal ein bisschen aus, was passiert. Der Compiler ist ja schnell. :wink:

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1435
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Untergeordnete Klassen

Beitrag von fliegermichl »

Ausserdem würde ich das verschieben in eine eigene Methode packen.

Code: Alles auswählen

type
 TBlock = class
 private
  fMatrix : TMatrix;
 public
  constructor Create(x, y, z : Single);
  procedure  Place(x, y, z : Single); virtual;
  property Matrix : TMatrix read fMatrix write fMatrix;
 end;
 
 THolz = class ( TBlock )
 private
  fMaterial : TVector4F;
 end;
 
implementation

constructor TBlock.Create(x, y, z : Single);
begin
 Place(x, y, z);
end;

procedure TBlock.Place(x, y, z);
begin
 Matrix.Translate(x, y, z);
end;
Somit kann man das Objekt auch nachträglich noch verschieben.

Code: Alles auswählen

var 
 Holz : THolz;
 Block : TBlock;
begin
 Holz := THolz.Create(0, 0, 0);
 Block := THolz.Create(1, 1, 1);
 Holz.Place(-1, 0, 0);
 Block.Place(1, 0, 0);
 Holz.Free;
 Block.Free;
end.

Aloxen
Beiträge: 58
Registriert: Di 31. Mai 2022, 17:40

Re: Untergeordnete Klassen

Beitrag von Aloxen »

theo hat geschrieben:
Do 10. Nov 2022, 09:18
1. Du solltest den Unterschied zwischen Klasse und Objekt verstehen.
Eine Klasse ist nur ein Schnittmuster oder eine Bauanleitung. Eine Klasse hält noch keine Daten.
Erst das Objekt kann Daten halten.
Also wenn ich ein Objekt erstelle wird es dann nach dem Bauplan erstellt und das was ich als „Variablen“ in der Klasse definiert habe, wird dann eine Eigenschaft des erstellten Objekts. Das heißt das jedes Objekt von TBlock automatisch seinen eigenen Platz für die obj bekommt.

Ich hatte versucht den Konstruktor create zu nennen, allerdings kam immer eine Fehlermeldung wenn ich inherited an den Anfang gesetzt habe. Weiß jemand warum das passiert?

Die Idee Create und Place zu trennen nehme ich gern an. Vielen Dank.

Benutzeravatar
theo
Beiträge: 10497
Registriert: Mo 11. Sep 2006, 19:01

Re: Untergeordnete Klassen

Beitrag von theo »

Aloxen hat geschrieben:
Do 10. Nov 2022, 10:09
Also wenn ich ein Objekt erstelle wird es dann nach dem Bauplan erstellt und das was ich als „Variablen“ in der Klasse definiert habe, wird dann eine Eigenschaft des erstellten Objekts. Das heißt das jedes Objekt von TBlock automatisch seinen eigenen Platz für die obj bekommt.
Weil es den Konstruktor Create mit diesen Parametern in der Vorfahrklasse nicht gibt.

Du könntest es so machen, oder in diesem Falle "inherited" auch einfach weglassen, da die Vorfahrklasse ja nichts Besonderes macht in Create.

Code: Alles auswählen

constructor THolz.Create(x, y, z: real);
begin
  inherited Create;
end;

Aloxen
Beiträge: 58
Registriert: Di 31. Mai 2022, 17:40

Re: Untergeordnete Klassen

Beitrag von Aloxen »

Danke Theo.

Es hat sich schon wieder eine neue Frage ergeben. Ich habe jetzt folgende Klassenstruktur

Code: Alles auswählen

type
   TBlock = class
    private
      F_obj: TMatrix;
    public
      property obj:TMatrix read F_Obj write F_Obj;
  end;

{------------------------------------------------------------------------------}
                              {Blocktypes}
{------------------------------------------------------------------------------}
{--Holz--}
type
   TWood =  class(TBlock)
     private
       F_m_r_i_R:TVector4f;
       F_texture_ID:integer;
     public
       property m_r_i_R:TVector4f read F_m_r_i_R write F_m_r_i_R;
       property texture_ID:integer read F_texture_ID write F_texture_ID;
       constructor create(x,y,z:real);
       procedure moveTo(x,y,z:real);
   end;
{--Holz--}
type
  TBrick =  class(TBlock)
    private
      F_m_r_i_R:TVector4f;
      F_texture_ID:integer;
    public
      property m_r_i_R:TVector4f read F_m_r_i_R write F_m_r_i_R;
      property texture_ID:integer read F_texture_ID write F_texture_ID;
      constructor create(x,y,z:real);
      procedure moveTo(x,y,z:real);
  end;
implementation
{--Holz--}
constructor TWood.create(x,y,z:real);
begin
  inherited create;
  moveTo(x,y,z);

  //Material
  F_m_r_i_R[0]:=0.0;      //Metallic
  F_m_r_i_R[1]:=1.0;      //Reflectance
  F_m_r_i_R[3]:=8.0;      //Roughness
  //Texture ID
  F_texture_ID:=1;
end;
procedure TWood.moveTo(x,y,z:real);
begin
  inherited;
  self.obj.Identity;
  self.obj.Translate(x,y,z);
end;

{--Brick--}
constructor TBrick.create(x,y,z:real);
begin
  inherited create;
  moveTo(x,y,z);

  //Material
  F_m_r_i_R[0]:=0.0;      //Metallic
  F_m_r_i_R[1]:=1.0;      //Reflectance
  F_m_r_i_R[3]:=8.0;      //Roughness
  //Texture ID
  F_texture_ID:=2;
end;
procedure TBrick.moveTo(x,y,z:real);
begin
  inherited;
  self.obj.Identity;
  self.obj.Translate(x,y,z);
end;                   
Ich habe ja wie gesagt die Liste mit allen Blöcken. Wenn ich die unterschiedlichen Blöcke auf dem Screen zeichnen möchte brauche ich die Texture_ID. Jede Untergruppe (Holz, Brick, Dirt etc.) Soll ihre eigene Texture ID haben, die ich im Konstruktor festlege.

Die Blockliste mit den Unterschiedlichen Blöcken habe ich so wie oben angewant. Wie greife ich jetzt auf die TextureID von einem bestimten Item der Blockliste zu? Ich darf die Texture_ID nicht auswählen, weil die Blocklist ja ein Array von TBlock und nicht THolz oder so ist.

Ich suche nach:

Code: Alles auswählen

Ablocklist[1].Texture_ID

Benutzeravatar
theo
Beiträge: 10497
Registriert: Mo 11. Sep 2006, 19:01

Re: Untergeordnete Klassen

Beitrag von theo »

Warum legst du den Code, der für alle gleich ist nicht in die Vorfahrklasse?

Code: Alles auswählen

      property m_r_i_R:TVector4f read F_m_r_i_R write F_m_r_i_R;
      property texture_ID:integer read F_texture_ID write F_texture_ID;
      procedure moveTo(x,y,z:real);
Gehört alles in TBlock.
Dann löst sich auch dein Problem wie von selbst. Probier's aus!

Ansonsten hiesse das Zauberwort "Typecasting", aber mach es wie vorher gesagt.

Aloxen
Beiträge: 58
Registriert: Di 31. Mai 2022, 17:40

Re: Untergeordnete Klassen

Beitrag von Aloxen »

Das hat Funktioniert. Ich hatte die TextureID in die Untergeordnete Klasse gepackt, weil ich dachte dass es ja eine Eigenschaft von dem Objekt holz ist, die nur THolz hat, ich habe aber vergessen, dass ich wenn ich THolz dann letztendlich erstelle auch die TBlock "Variablen" mit den Konstructor speziell zuweisen kann. Vielen Dank

Aloxen
Beiträge: 58
Registriert: Di 31. Mai 2022, 17:40

Re: Untergeordnete Klassen

Beitrag von Aloxen »

theo hat geschrieben:
Do 17. Nov 2022, 22:52
@theo
Ich bin wiedermal bei Klassen angelangt und ich stehe vor den Problem, dass ich eine Procedure geschrieben habe, die Blöcke eines Typs innerhalb eines definierten Bereichs platzieren soll. Wie muss ich jetzt den Typ angeben?
So oder so ähnlich soll die Procedure aussehen:

Code: Alles auswählen

procedure TForm1.place([b]BlockType:TBlock[/b];x1,y1,z1,x2,y2,z2:integer);
Das Problem ist, dass TBlock nicht die Art Block enthält, sondern nur die Übergruppe für alle unterschiedlichen BLockarten. Gibt es einen Weg zu sagen, dass alles was TBlock vererbt bekommen hat hier eingegeben werden kann? Später sollte eine Eingabe dann so aussehen:

Code: Alles auswählen

place(TWood,2,0,2,-2,0,-2);

Antworten