Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Richtiges Mittel anstatt virtueller generischer Variable (https://www.delphipraxis.net/196152-richtiges-mittel-anstatt-virtueller-generischer-variable.html)

hzzm 26. Apr 2018 13:32

Delphi-Version: 10 Seattle

Richtiges Mittel anstatt virtueller generischer Variable
 
Guten Tag,

mir fehlt gerade irgendwie der Griff zum richtigen Mittel fuer folgende Situation:

Delphi-Quellcode:
type
  TZitrone = packed Record
    Breite: Integer;
    Saeuerlichkeit: Double;
  End;

  TErdnuss = packed Record
    Breite: Integer;
    Schale: Boolean;
    Geschmack: String;
  End;


  TSnack = class
    GegessenVon: String;
    virtual Inhalt: TArray<T: TZitrone, TErdnuss>;
    procedure NulleBreiten;
  End;

implementation

  procedure TSnack.NulleBreiten;
  var
    I: Integer;
  begin
     for I:=0 to High(Inhalt) do
       Breite := 0;
  end;
Selbstverstaendlich funktioniert das so wie geschrieben nicht. Ich braeuchte eben die korrekte Syntax/den korrekten Aufbau anstatt
Delphi-Quellcode:
virtual Inhalt: TArray<T: TZitrone, TErdnuss>;
Ich will also, dass "Inhalt" entweder ein TArray<TZitrone> oder ein TArray<TErdnuss> sein muss.
Ausserdem will ich von TSnack-Klassenmethoden, die nicht auf die spezifischen Eigenschaften Saeuerlichkeit, Schale, Geschmack zugreifen, allgemein durch das Array iterieren koennen.

Ich habe es mit Vererbung probiert, TErdnussSnack = class(TSnack), nur in Erdnuss-Snack dann das TArray<TErdnuss> deklariert. Dann existiert aber kein Element in TSnack, durch das ich allgemein iterieren koennte.

Vielleicht kennt jemand einen besseren Aufbau/Ansatz oder die gesuchte Syntax?

Danke

TiGü 26. Apr 2018 13:49

AW: Richtiges Mittel anstatt virtueller generischer Variable
 
Delphi-Quellcode:
type
  TFood = class
    Breite: Integer;
  end;

  TZitrone = class(TFood)
    Saeuerlichkeit: Double;
  end;

  TErdnuss = class(TFood)
    Schale: Boolean;
    Geschmack: string;
  end;

  TSnack = class
  private
    FInhalt: TArray<TFood>;
  public
    GegessenVon: string;
    property Inhalt: TArray<TFood> read FInhalt write FInhalt;
    procedure NulleBreiten;
  end;

procedure TSnack.NulleBreiten;
var
  I: Integer;
begin
  for I := low(Inhalt) to high(Inhalt) do
    Inhalt[I].Breite := 0;
end;

freimatz 26. Apr 2018 13:52

AW: Richtiges Mittel anstatt virtueller generischer Variable
 
Genau - nimm Klassen statt records.
records (und Aufzählungstypen) lassen sich leidern nicht vererben.

hzzm 27. Apr 2018 11:38

AW: Richtiges Mittel anstatt virtueller generischer Variable
 
Wie waere es denn, wenn ich noch 2 ueberliegende Objekte brauche, die jeweils die spezifischen Eigenschaften von TZitrone und TErdnuss brauchen:
Delphi-Quellcode:
type
  TFood = class
    Breite: Integer;
  end;

  TZitrone = class(TFood)
    Saeuerlichkeit: Double;
  end;

  TErdnuss = class(TFood)
    Schale: Boolean;
    Geschmack: string;
  end;

  TSnack = class
  private
    FInhalt: TArray<TFood>;
  public
    GegessenVon: string;
    property Inhalt: TArray<TFood> read FInhalt write FInhalt;
    procedure NulleBreiten; // allg. gueltig fuer TZitrone und TErdnuss
  end;

  TZitronenSnack = class(TSnack)
  private
    FInhalt: TArray<TZitrone>;
  public
    property Inhalt: TArray<TZitrone> read FInhalt write FInhalt;
    procedure SauerNullen;
  End;

procedure TSnack.NulleBreiten;
var
  I: Integer;
begin
  for I := low(Inhalt) to high(Inhalt) do
    Inhalt[I].Breite := 0;
end;

procedure TZitronenSnack.SauerNullen;
begin
  for I := low(Inhalt) to high(Inhalt) do
    Inhalt[I].Saeuerlichkeit := 0.0;
end;
Jetzt habe ich
Delphi-Quellcode:
Inhalt
ja sowohl in der Erbenden als auch Vererbenden klasse.
Funktioniert das so, oder waere da eine andere Struktur angebracht?

stahli 27. Apr 2018 12:03

AW: Richtiges Mittel anstatt virtueller generischer Variable
 
Die neue Eigenschaft "Inhalt" würde die alte verdecken (bin jetzt gar nicht sicher, ob das überhaupt kompilieren würde).
Also sinnvoll wäre das nicht.

Du könntest "Inhalt" in TSnack deklarieren und so belassen. In den abgeleiteten Klassen könntest Du dann dessen Items (TFood) in TErdnuss casten und mit dem Cast weiter artbeiten. Allerdings könntest Du dann auch einfach mit TObjectList statt mit generischen Listen arbeiten.

Oder Du lässt "Inhalt" aus TSnack raus und führst erst in allen abgeleiteten Klassen eine spezifische Eigenschaft "Inhalt" ein.
Dann hättest Du in der Basisklasse TSnack wirklich nur noch Eigenschaften und Methoden, die auch in allen abgeleiteten Klassen noch gleich sind.
Aber Du könntest dann in der Basisklasse nichts unterbringen, was irgendwie mit dem "Inhalt" umgeht.

Dein vereinfachtes Beispiel ist schon etwas zu abstrakt, um genau einschätzen zu können, was für Dich der beste Ansatz ist.
Eventuell könnte auch die Benutzung von Interfaces Sinn machen, aber dafür muss man sich damit erst mal intensiver damit beschäftigen.
Da gibt es eine gewisse Lernkurve.

FaTaLGuiLLoTiNe 27. Apr 2018 12:06

AW: Richtiges Mittel anstatt virtueller generischer Variable
 
Du könntest TSnack ebenfalls parametrisieren (= generisch machen).

hzzm 27. Apr 2018 12:41

AW: Richtiges Mittel anstatt virtueller generischer Variable
 
Zitat:

Zitat von stahli (Beitrag 1400753)
Interfaces ...
Da gibt es eine gewisse Lernkurve.

Das waer jetzt nicht so das Problem, da ich Interfaces schon an einigen anderen Stellen exzessiv verwende.

Zitat:

Zitat von stahli (Beitrag 1400753)
Du könntest "Inhalt" in TSnack deklarieren und so belassen. In den abgeleiteten Klassen könntest Du dann dessen Items (TFood) in TErdnuss casten und mit dem Cast weiter artbeiten. Allerdings könntest Du dann auch einfach mit TObjectList statt mit generischen Listen arbeiten.

Klingt verlockend: Ich erstelle diese TArray<TFood>'s nur als TArray<TErdnuss> oder TArray<TZitrone>, nie als TArray<TFood>; ausserdem immer ueber TErdnussSnack oder TZitronenSnack. Ist es bei den Casts dennoch sichergestellt, dass die zusaetzlichen spezifischen Eigenschaften nie verloren gehen, solange ich Create nie ueber TFood laufen lasse?

Zacherl 27. Apr 2018 12:48

AW: Richtiges Mittel anstatt virtueller generischer Variable
 
Zitat:

Zitat von hzzm (Beitrag 1400759)
Zitat:

Zitat von stahli (Beitrag 1400753)
Du könntest "Inhalt" in TSnack deklarieren und so belassen. In den abgeleiteten Klassen könntest Du dann dessen Items (TFood) in TErdnuss casten und mit dem Cast weiter artbeiten. Allerdings könntest Du dann auch einfach mit TObjectList statt mit generischen Listen arbeiten.

Klingt verlockend: Ich erstelle diese TArray<TFood>'s nur als TArray<TErdnuss> oder TArray<TZitrone>, nie als TArray<TFood>; ausserdem immer ueber TErdnussSnack oder TZitronenSnack. Ist es bei den Casts dennoch sichergestellt, dass die zusaetzlichen spezifischen Eigenschaften nie verloren gehen, solange ich Create nie ueber TFood laufen lasse?

Mhh, das verstehe ich jetzt nicht. Casten musst du eigentlich gar nicht, wenn du deine Klasse so deklarierst:
Delphi-Quellcode:
type
  TFood = class
    Breite: Integer;
  end;

  TZitrone = class(TFood)
    Saeuerlichkeit: Double;
  end;

  TErdnuss = class(TFood)
    Schale: Boolean;
    Geschmack: string;
  end;

  TSnack<T: TFood> = class
  private
    FInhalt: TArray<T>;
  public
    GegessenVon: string;
    property Inhalt: TArray<T> read FInhalt write FInhalt;
    procedure NulleBreiten; // allg. gueltig fuer TZitrone und TErdnuss
  end;

  TZitronenSnack = class(TSnack<TZitrone>);
  TErdnussSnack = class(TSnack<TErdnuss>);
Die beiden spezialisierten Klassen können jetzt jeweils nur entweder 0..n Zitronen oder 0..n Erdnüsse enthalten.
Delphi-Quellcode:
TMixedSnack = TSnack<TFood>
wäre weiterhin eine Möglichkeit, die beide Speisen enthalten kann.

Edit:
Achso du meinst vermutlich beim Erstellen. Wenn die Klasseninstanz konkret als z.B.
Delphi-Quellcode:
TZitrone.Create
erstellt wurde, hast du selbstverständlich weiterhin immer alle spezifischen Eigenschaften. Falls benötigt, könntest du auch den Constructor von
Delphi-Quellcode:
TFood
als
Delphi-Quellcode:
virtual
deklarieren. Das würde dir erlauben Objekte auch über die Meta-Klasse
Delphi-Quellcode:
TFoodClass = class of TFood
zu erzeugen.

stahli 27. Apr 2018 12:55

AW: Richtiges Mittel anstatt virtueller generischer Variable
 
Ich gehe ja davon aus, dass ein Erdnußsnack nicht nur Erdnüsse als Inhalt und ein Zitronensnack nicht nur Zitronen.
Insofern sollten doch die Inhaltsbestandteile variabel sein - oder?

Insofern beschreibe doch mal, was für ein Projekt Du tatsächlich aufbauen willst.

...


Ja, der Beitrag von Zacherl macht Sinn. :thumb:

Zacherl 27. Apr 2018 12:57

AW: Richtiges Mittel anstatt virtueller generischer Variable
 
Zitat:

Zitat von stahli (Beitrag 1400763)
Ich gehe ja davon aus, dass ein Erdnußsnack nicht nur Erdnüsse als Inhalt und ein Zitronensnack nicht nur Zitronen.
Insofern sollten doch die Inhaltsbestandteile variabel sein - oder?

Insofern beschreibe doch mal, was für ein Projekt Du tatsächlich aufbauen willst.

:thumb: Jaa, die Logik hinter dem beschriebenen Klassendesign macht für mich auch bisher noch keinen wirklichen Sinn.


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:37 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