AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Vererbung und Polymorphie

Ein Thema von StepByStep · begonnen am 18. Dez 2014 · letzter Beitrag vom 19. Dez 2014
Antwort Antwort
Benutzerbild von Neutral General
Neutral General

Registriert seit: 16. Jan 2004
Ort: Bendorf
5.219 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#1

AW: Vererbung und Polymorphie

  Alt 18. Dez 2014, 10:18
Hallo,

Zu Problem 1:
Im Button-Click fragst du die Radio-Group ab. Je nachdem erstellst du eine Instanz der gewünschten Klasse und fügst diese zu deiner Menschenliste hinzu.
In diesem Schritt musst du natürlich explizit auf die Felder der abgeleiteten Klassen zugreifen.

Zu Problem 2:
Es ist doch egal wie viele Werte die einzelnen Objekte in der Menschenliste haben. Da in der Liste ja nicht die kompletten Objekte sondern jeweils nur Pointer (4 bzw. 8 Byte groß) auf die Objekte gespeichert werden hat das überhaupt keine Auswirkung auf die Liste selbst.

Edit: Oder was wahrscheinlich noch besser wäre wäre eine Funktion in der Art wie Mikkey es vorgeschlagen hat, die dafür sorgt dass über eine virtuelle Methode das Objekt selbst dafür sorgt wie es z.B. ausgegeben wird (wäre vor allem für Problem 3 sehr praktisch)

Zu Problem 3:
In diesem Fall würdest du die Menschenliste mit einer Schleife durchlaufen und nur die Objekte in irgendeiner Weise darstellen/anzeigen die von der Klasse TArbeiter abgeleitet sind:

Delphi-Quellcode:
for i:= 0 to Menschenliste.Count-1 do
begin
  if Menschenliste[i] is TArbeiter then
    DisplayMensch(Menschenliste[i]);
end;

// oder besser:

for i:= 0 to Menschenliste.Count-1 do
begin
  if Menschenliste[i] is TArbeiter then
    Menschenliste[i].Display(AnzeigePanel); // o.ä.
end;
Generelles:
Wenn du auf Objekte in der Liste zugreifst kannst du erstmal nur auf die Felder zugreifen die in TMensch deklariert wurden. Möchtest du Felder abgeleiteter Klassen lesen/schreiben musst du vorher prüfen von welcher Klasse das Objekt abgeleitet ist (s.o.) und danach das Objekt casten.

Delphi-Quellcode:
var arbeiter: TArbeiter;
begin
  if Menschenliste[0] is TArbeiter then
  begin
    arbeiter := TArbeiter(Menschenliste[0]);
    arbeiter.Stundenlohn := 15.0;
  end;
end;
Ich bin mir aber auch generell nicht ganz sicher was du mit deinen Fragen meinst. Aber ich glaube du denkst z.T. falsch bzw. zu kompliziert.
Michael
"Programmers talk about software development on weekends, vacations, and over meals not because they lack imagination,
but because their imagination reveals worlds that others cannot see."

Geändert von Neutral General (18. Dez 2014 um 10:23 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.666 Beiträge
 
Delphi 12 Athens
 
#2

AW: Vererbung und Polymorphie

  Alt 18. Dez 2014, 10:36
Wenn man der Oberklasse eine Handvoll (ggf. abstrakter) Methoden spendiert, könnte man sich außer bei der Filterung doch die ganzen "is"-Abfragen sparen.
Delphi-Quellcode:
type
  TOberdings = class
  public
    procedure SetValues; virtual; abstract;
    procedure DisplayValues; virtual; abstract;
  end;

  TErstesUnterdings = class(TOberdings)
  public
    procedure SetValues; override;
    procedure DisplayValues; override;
  end;
  
  TZweitesUnterdings = class(TOberdings)
  public
    procedure SetValues; override;
    procedure DisplayValues; override;
  end;
Wenn man nun eine Liste von TOberdings hat, kann man die Methoden SetValues und DisplayValues für jedes einzelne Element aufrufen, ohne sich um dessen konkreten Unterklassentyp scheren zu müssen. Weiterhin wäre auch der Ansatz über Interfaces denkbar, das ist dann noch einen Tacken abstrakter, da man noch nicht einmal eine bestimmte Klassenhierarchie einhalten müsste.
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.358 Beiträge
 
Delphi 11 Alexandria
 
#3

AW: Vererbung und Polymorphie

  Alt 18. Dez 2014, 11:34
Ich will auch mal zur Verwirrung beitragen...

Wenn Du Menschen in eine Liste speicherst steht dort drin nur
-> Zeiger auf Objekt
-> Zeiger auf Objekt
-> Zeiger auf Objekt
-> Zeiger auf Objekt

Du kannst Dir dann auch nur Objekte dort heraus holen.

Wenn Du dort nur Menschen gespeicherst hast kannst Du einfach die Objekte in Menschen casten -> Mensch := TMensch(List[0]); Falls der erste Mensch tatsächlich ein Schüler war kannst Du an die Schülereigenschaften nicht heran.
Wenn der erste Eintrag ein Auto war, dann knallt es (bestenfalls sofort oder mit unvorhersehbaren Folgen später), da u.U. Speicherplätze beschrieben werden, die gar nicht zu dem eigentlichen Objekt gehören.


Wenn Du Menschen, Schüler und Arbeiter in der Liste hast musst Du prüfen, was Du gerade vorliegen hast:

Delphi-Quellcode:
O := List[0];
if (O is TSchueler) then
  Schueler := (O as TSchueler)
else
if (O is TArbeiter) then
  Arbeiter := (O as TArbeiter)
else
if (O is TMensch) then
  Mensch := (O as TMensch);

Generische Listen akzeptieren nur bestimmte Objekte und geben die entsprechend wieder zurück. Bei einer generischen Menschenliste würdest Du also immer einen TMensch zurück erhalten.
Solche Listen sind u.a. nützlich, wenn man eine bestimmte Klasse speichern und sich das ständige Casten ersparen will.


Ein kurzer Ausflug, weil Du "Polymorphie" geschrieben hast:
Letztlich kannst Du Dich auch mal zu Schnittstellen (Interfaces) einlesen.
Da kann man völlig unterschiedliche Objekte speichern und weiter verarbeiten, die aber einheitliche Eigenschaften haben. Z.B. hätte ein Auto und ein Motorrad jeweils eine Schnittstelle IVerbrennungsmotor.
Der Verbrennungsmotor kann dann gestartet werden (Verbrennungsmotor.Start), ohne dass der Zündschlüssel wissen muss, ob am Motor ein Auto hängt oder ein Motorrad.
Dadurch kann man Klassen voneinander entkoppeln und flexibel mit ihnen umgehen.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)

Geändert von stahli (18. Dez 2014 um 11:52 Uhr)
  Mit Zitat antworten Zitat
StepByStep

Registriert seit: 12. Nov 2014
Ort: Schleswig-Holstein
61 Beiträge
 
Delphi 7 Professional
 
#4

AW: Vererbung und Polymorphie

  Alt 18. Dez 2014, 12:25
Mahlzeit ,

danke für die Antworten. Die Lösung für mein erstes Problem, was DeddyH geschrieben hat, wende ich jetzt auch an, nur habe ich kleine Schwierigkeiten.
Ich habe das ganze mal an einem Beispiel ausprobiert.

Delphi-Quellcode:
unit Schach;

interface

uses
  system.generics.collections,
  Dialogs,
  system.sysutils;

type
  TSchachfigur = class
    Reichweite: integer;
    procedure setreichweite();
    function InString(): string; virtual;
  end;

type
  TSchachBauer = class(TSchachfigur)
    Form: string;
    procedure setform();
    function InString(): string; override;
  end;

type
  TSchachSpringer = class(TSchachfigur)
    Position: integer;
    procedure setposition();
    function InString(): string; override;
  end;

type
  Tschachspiel = class
    fschachfiguren: Tobjectlist<TSchachfigur>;
    constructor create;
  end;

implementation

function TSchachbauer.InString: string;
begin
  result := Form;
end;

procedure TSchachBauer.setform;
begin
  Form := 'kantig';
end;

constructor Tschachspiel.create;
var
  I: integer;
  temp: TSchachfigur;
begin
  fschachfiguren := Tobjectlist<TSchachfigur>.create;

  temp := TSchachBauer.create;
  fschachfiguren.add(temp);

  temp := TSchachSpringer.create;
  fschachfiguren.add(temp);

  for I := 0 to fschachfiguren.Count - 1 do
  begin
    showmessage(fschachfiguren[I].InString);
  end;

end;

function TSchachSpringer.InString: string;
begin
  result := IntToStr(Position);
end;

procedure TSchachSpringer.setposition;
begin
  Position := 1;
end;

function TSchachfigur.InString: string;
begin
  result := IntToStr(Reichweite);
end;

procedure TSchachfigur.setreichweite;
begin
  Reichweite := 7;
end;

end.
Ich habe versucht das ganze anhand eines Schachspieles zu probieren, bevor ich mir mein eigentliches Programm ganz zerlege.
Aber ich bekomme in der Messagebox einmal nichts und dann einmal "0". Woran liegt das?
So wie das Programm aufgebaut ist, ist auch mein eigentliches Programm.

Gruß
Jan

Edit: Ich konnte das Problem gerade eben selber lösen, indem ich nicht den Umweg über die Set-Procedure gemacht habe. Aber wie geht das mit dieser?
UND bei der Ausgabe wird nicht der Wert von Schachfigur ausgegeben. Wie bekomme ich es hin, dass dieser dann auch ausgegeben wird?
Jan

Geändert von StepByStep (18. Dez 2014 um 12:39 Uhr)
  Mit Zitat antworten Zitat
Bjoerk

Registriert seit: 28. Feb 2011
Ort: Mannheim
1.384 Beiträge
 
Delphi 10.4 Sydney
 
#5

AW: Vererbung und Polymorphie

  Alt 18. Dez 2014, 13:28
Ich würde vorschlagen, du verlegst die Adds und Castings weitegehend in die Liste, dann tust du dir anschließend leichter. Mit Generics geht das wahrscheinlich noch einfacher (keine Ahnung, hab D2007).
Delphi-Quellcode:
procedure TMenschTestForm.SomeButtonClick(Sender: TObject);
var
  Menschen: TMenschen;
  Index: integer;
begin
  Menschen := TMenschen.Create;
  try
    Index := Menschen.AddSportler;
    Menschen.Sportler[Index].SomeProp := 'Fußball';
    ShowMessage(IntToStr(Menschen.SportlerCount));
  finally
    Menschen.Free;
  end;
end;
Delphi-Quellcode:
  TMenschen = class(TObjectList)
  private
    function GetArbeiter(Index: integer): TArbeiter;
    function GetAzubi(Index: integer): TAzubi;
    function GetJob(Index: integer): TJob;
    function GetMensch(Index: integer): TMensch;
    function GetSchueler(Index: integer): TSchueler;
    function GetSchule(Index: integer): TSchule;
    function GetSportler(Index: integer): TSportler;
    function GetArbeiterCount: integer;
    function GetAzubiCount: integer;
    function GetJobCount: integer;
    function GetMenschCount: integer;
    function GetSchuelerCount: integer;
    function GetSchuleCount: integer;
    function GetSportlerCount: integer;
    function GetIsArbeiter(Index: integer): boolean;
    function GetIsAzubi(Index: integer): boolean;
    function GetIsJob(Index: integer): boolean;
    function GetIsMensch(Index: integer): boolean;
    function GetIsSchueler(Index: integer): boolean;
    function GetIsSchule(Index: integer): boolean;
    function GetIsSportler(Index: integer): boolean;
  public
    function AddMensch: integer;
    function AddJob: integer;
    function AddSchule: integer;
    function AddArbeiter: integer;
    function AddSportler: integer;
    function AddAzubi: integer;
    function AddSchueler: integer;

    property MenschCount: integer read GetMenschCount;
    property JobCount: integer read GetJobCount;
    property SchuleCount: integer read GetSchuleCount;
    property ArbeiterCount: integer read GetArbeiterCount;
    property SportlerCount: integer read GetSportlerCount;
    property AzubiCount: integer read GetAzubiCount;
    property SchuelerCount: integer read GetSchuelerCount;

    property Mensch[Index: integer]: TMensch read GetMensch;
    property Job[Index: integer]: TJob read GetJob;
    property Schule[Index: integer]: TSchule read GetSchule;
    property Arbeiter[Index: integer]: TArbeiter read GetArbeiter;
    property Sportler[Index: integer]: TSportler read GetSportler;
    property Azubi[Index: integer]: TAzubi read GetAzubi;
    property Schueler[Index: integer]: TSchueler read GetSchueler;

    property IsMensch[Index: integer]: boolean read GetIsMensch;
    property IsJob[Index: integer]: boolean read GetIsJob;
    property IsSchule[Index: integer]: boolean read GetIsSchule;
    property IsArbeiter[Index: integer]: boolean read GetIsArbeiter;
    property IsSportler[Index: integer]: boolean read GetIsSportler;
    property IsAzubi[Index: integer]: boolean read GetIsAzubi;
    property IsSchueler[Index: integer]: boolean read GetIsSchueler;
  end;

implementation

{ TMenschen }

function TMenschen.AddArbeiter: integer;
begin
  Result := Add(TArbeiter.Create);
end;
function TMenschen.AddAzubi: integer;
begin
  Result := Add(TAzubi.Create);
end;
function TMenschen.AddJob: integer;
begin
  Result := Add(TJob.Create);
end;
function TMenschen.AddMensch: integer;
begin
  Result := Add(TMensch.Create);
end;
function TMenschen.AddSchule: integer;
begin
  Result := Add(TSchule.Create);
end;
function TMenschen.AddSchueler: integer;
begin
  Result := Add(TSchueler.Create);
end;
function TMenschen.AddSportler: integer;
begin
  Result := Add(TSportler.Create);
end;

function TMenschen.GetArbeiter(Index: integer): TArbeiter;
begin
  if IsArbeiter[Index] then
    Result := TArbeiter(Items[Index])
  else
    raise Exception.Create('GetArbeiter');
end;
function TMenschen.GetAzubi(Index: integer): TAzubi;
begin
  if IsAzubi[Index] then
    Result := TAzubi(Items[Index])
  else
    raise Exception.Create('GetAzubi');
end;
function TMenschen.GetSchueler(Index: integer): TSchueler;
begin
  if IsSchueler[Index] then
    Result := TSchueler(Items[Index])
  else
    raise Exception.Create('GetSchueler');
end;
function TMenschen.GetJob(Index: integer): TJob;
begin
  if IsJob[Index] then
    Result := TJob(Items[Index])
  else
    raise Exception.Create('GetJob');
end;
function TMenschen.GetMensch(Index: integer): TMensch;
begin
  if IsMensch[Index] then
    Result := TMensch(Items[Index])
  else
    raise Exception.Create('GetMensch');
end;
function TMenschen.GetSchule(Index: integer): TSchule;
begin
  if IsSchule[Index] then
    Result := TSchule(Items[Index])
  else
    raise Exception.Create('GetSchule');
end;
function TMenschen.GetSportler(Index: integer): TSportler;
begin
  if IsSportler[Index] then
    Result := TSportler(Items[Index])
  else
    raise Exception.Create('GetSportler');
end;

function TMenschen.GetArbeiterCount: integer;
var
  I: integer;
begin
  Result := 0;
  for I := 0 to Count - 1 do
    if IsArbeiter[I] then
      Inc(Result);
end;
function TMenschen.GetAzubiCount: integer;
var
  I: integer;
begin
  Result := 0;
  for I := 0 to Count - 1 do
    if IsAzubi[I] then
      Inc(Result);
end;
function TMenschen.GetJobCount: integer;
var
  I: integer;
begin
  Result := 0;
  for I := 0 to Count - 1 do
    if IsJob[I] then
      Inc(Result);
end;
function TMenschen.GetMenschCount: integer;
var
  I: integer;
begin
  Result := 0;
  for I := 0 to Count - 1 do
    if IsMensch[I] then
      Inc(Result);
end;
function TMenschen.GetSchuleCount: integer;
var
  I: integer;
begin
  Result := 0;
  for I := 0 to Count - 1 do
    if IsSchule[I] then
      Inc(Result);
end;
function TMenschen.GetSchuelerCount: integer;
var
  I: integer;
begin
  Result := 0;
  for I := 0 to Count - 1 do
    if IsSchueler[I] then
      Inc(Result);
end;
function TMenschen.GetSportlerCount: integer;
var
  I: integer;
begin
  Result := 0;
  for I := 0 to Count - 1 do
    if IsSportler[I] then
      Inc(Result);
end;

function TMenschen.GetIsArbeiter(Index: integer): boolean;
begin
  Result := Items[Index] is TArbeiter;
end;
function TMenschen.GetIsAzubi(Index: integer): boolean;
begin
  Result := Items[Index] is TAzubi;
end;
function TMenschen.GetIsJob(Index: integer): boolean;
begin
  Result := Items[Index] is TJob;
end;
function TMenschen.GetIsMensch(Index: integer): boolean;
begin
  Result := Items[Index] is TMensch;
end;
function TMenschen.GetIsSchule(Index: integer): boolean;
begin
  Result := Items[Index] is TSchule;
end;
function TMenschen.GetIsSchueler(Index: integer): boolean;
begin
  Result := Items[Index] is TSchueler;
end;
function TMenschen.GetIsSportler(Index: integer): boolean;
begin
  Result := Items[Index] is TSportler;
end;

Geändert von Bjoerk (18. Dez 2014 um 13:43 Uhr) Grund: Menschen.Sportler[Index].SomeProp := 'Fußball';
  Mit Zitat antworten Zitat
Jumpy

Registriert seit: 9. Dez 2010
Ort: Mönchengladbach
1.740 Beiträge
 
Delphi 6 Enterprise
 
#6

AW: Vererbung und Polymorphie

  Alt 18. Dez 2014, 13:37
Edit: Ich konnte das Problem gerade eben selber lösen, indem ich nicht den Umweg über die Set-Procedure gemacht habe. Aber wie geht das mit dieser?
UND bei der Ausgabe wird nicht der Wert von Schachfigur ausgegeben. Wie bekomme ich es hin, dass dieser dann auch ausgegeben wird?
Das Beispiel ist blöd. Man muss schauen, was alle Teile gemeinsam haben (Position,Form,Reichweite) und was anders ist (vllt. erlaubte Bewegungsart oder so) dann wird auch klarer was warum nicht geht. Aber sei es drum, nehmen wir das Beispiel wie es ist.

Du könntest den Figuren jeweile einen eigenen Konstruktor spendieren, der (um im Beispiel zu bleiben) mal die Form, mal die Position setzt. Oder, um mal Polymorphie auszunutzen: Die Basisklasse bekommt eine virtuelle abstakte Prozedur "Initialisieren" oder so. Die Prozedur wird in jeder Klasse anders überschrieben und setzt halt einmal die Form, ein anderes mal die Position, was weiß ich.

Dann kannst du folgendes schreiben:
Code:
var
  I: integer;
  temp: TSchachfigur;
begin
  fschachfiguren := Tobjectlist<TSchachfigur>.create;

  temp := TSchachBauer.create;
  temp.Initialisieren;
  fschachfiguren.add(temp);

[...]
Und schon haben deine Figuren auch was, das sie beim ToString ausgeben können.

------------------------------------

Du solltest aber besser auf dein ursprüngliches Problem zurückkommen: Was brauchst du wirklich für Klassen und wofür. Dann kann man vllt. besser helfen. Worin sollen sich die einzelnen Menschen unterscheiden?
Ralph
  Mit Zitat antworten Zitat
StepByStep

Registriert seit: 12. Nov 2014
Ort: Schleswig-Holstein
61 Beiträge
 
Delphi 7 Professional
 
#7

AW: Vererbung und Polymorphie

  Alt 18. Dez 2014, 14:17
Hallo Jumpy,

ich komme auf deinen Ratschlag mal zurück.

Ich habe eine Klasse TMensch:

Delphi-Quellcode:
    FHerkunft: string;
    FName: string;
    FGeburtsdatum: Tdate;
    FGroeße: extended;
    FGeschlecht: boolean;
    FFamilienstand: string;
Dann eine Klasse TJob:

Delphi-Quellcode:
    FGehalt: extended;
    FArbeitszeit: integer;
    FBeruf: string;
Dann eine Klasse TSchule:

Delphi-Quellcode:
    FSchulfaecher: string;
    FNotendurchschnitt: extended;
    FSchulform: string;
Dann eine Klasse TArbeiter:

    FChef: boolean;

Dann eine Klasse TSportler:

Delphi-Quellcode:
    FSportart: string;
    FErrungenschaften: string;
Dann eine Klasse TAzubi:

Delphi-Quellcode:
    FNotendurchschnitt: extended;
    FSchulfaecher: string;
    FSchulform: string;
Dann eine Klasse TSchueler:

Delphi-Quellcode:
    FKlassenfahrt: boolean;
    FKlassensprecher: boolean;
Das sind alle meine Klassen mit den Variablen. Ein einem extra Formular lese ich Editfelder aus und möchte die gerne in eine Variable von TMensch schreiben, was aber nicht geht, da TMensch die Klassenvariablen aber nicht kennt. Ich hoffe das ist jetzt verständlich.

Gruß
Jan
Jan
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.358 Beiträge
 
Delphi 11 Alexandria
 
#8

AW: Vererbung und Polymorphie

  Alt 18. Dez 2014, 14:29
Also mir ist nicht klar, was Du genau willst...

Den Inhalt von EditBeruf kannst Du nicht ein ein TMensch-Objekt schreiben.
Du musst dafür ein TJob-Objekt (TAngestellter wäre sicher passender) vorliegen haben.

Andersrum kannst Du in ein TJob-Objekt auch alles schreiben, was in TMensch deklariert ist.

Oder geht es Dir eher darum, wie Du die Eingabeformulare organisieren sollst?
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Dejan Vu
(Gast)

n/a Beiträge
 
#9

AW: Vererbung und Polymorphie

  Alt 18. Dez 2014, 17:42
Das sind alle meine Klassen mit den Variablen. Ein einem extra Formular lese ich Editfelder aus und möchte die gerne in eine Variable von TMensch schreiben, was aber nicht geht, da TMensch die Klassenvariablen aber nicht kennt. Ich hoffe das ist jetzt verständlich.
Na du musst schon den konkreten Menschtypen instanziieren (Job, Schüler etc.) ist doch klar.

Das ist doch wie im richtigen Leben. Einen Deutschen sprichst Du deutsch an, einen Engländer englisch. Und einen 'Menschen'? Mit dem kannst Du nur in einer allen Menschen gemeinen Sprache sprechen (Mimik, Musik z.B.)

Na ja, hinkt vielleicht ein wenig.
  Mit Zitat antworten Zitat
Antwort Antwort

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:27 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