Delphi-PRAXiS
Seite 1 von 2  1 2   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Übung Polymorphie (https://www.delphipraxis.net/194429-uebung-polymorphie.html)

EdAdvokat 19. Nov 2017 16:14

Übung Polymorphie
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo, ich wage mich mal wieder ins Forum mit der Bitte, über meine kleine Übung zur Polymorphie zu sehen und mir ggf. einen Tip zu geben ob und wo ich was nicht richtig gemacht habe.
Auf einige Kleinigkeiten, wie der Prüfung ob die Werte größer 0 bzw. nur Zahlen sein dürfen habe ich hier verzichtet.
Meine Frage ist: habe ich das Prinzip der Polymorphie in Form der Klassen (TFigur, TRechteck, TDreieck) so richtig verstanden?
Vielen Dank im voraus.
Programm anbei

Delphi-Quellcode:
unit uBerechnung;

interface

uses Vcl.Dialogs;

type TFigur = class(TObject)
  private
    FSeiteA:Double;
    FSeiteB:Double;
    procedure SetSeiteA(A:Double);virtual;abstract;
    procedure SetSeiteB(B:Double);virtual;abstract;

    function getSeiteA:Double;virtual;abstract;
    function getSeiteB:Double;virtual;abstract;
    function getBerechneFl:Double;virtual;abstract;
end;

type TRechteck = class(TFigur)
  private
    procedure SetSeiteA(A:Double);override;
    procedure SetSeiteB(B:Double);override;
    function getSeiteA:Double;override;
    function getSeiteB:Double;override;
    function getBerechneFl:Double; override;
   public
    property SeiteA:Double read FSeiteA write FSeiteA;
    property SeiteB:Double read FSeiteB write FSeiteB;
    property BerechneFl:Double read getBerechneFl;
end;

type TDreieck = class(TRechteck)
  private
    procedure SetSeiteA(A:Double);override;
    procedure SetSeiteB(B:Double);override;
    function getSeiteA:Double;override;
    function getSeiteB:Double;override;
    function getBerechneFl:Double;override;
   public
    property SeiteA:Double read FSeiteA write FSeiteA;
    property SeiteB:Double read FSeiteB write FSeiteB;
    property BerechneFl:Double read getBerechneFl;
end;

implementation

{ TRechteck }


function TRechteck.getBerechneFl: Double;
begin
  result:=FSeiteA*FSeiteB;
end;

function TRechteck.getSeiteA: Double;
begin
  result:=FSeiteA;
end;

function TRechteck.getSeiteB: Double;
begin
  result:=FSeiteB;
end;

procedure TRechteck.SetSeiteA(A: Double);
begin
  FSeiteA:=A;
end;

procedure TRechteck.SetSeiteB(B: Double);
begin
  FSeiteB:=B;
end;


{ TDreieck }

function TDreieck.getBerechneFl: Double;
begin
  result:=FSeiteA*FSeiteB/2;
end;

function TDreieck.getSeiteA: Double;
begin
  result:=FSeiteA;
end;

function TDreieck.getSeiteB: Double;
begin
  result:=FSeiteB;
end;

procedure TDreieck.SetSeiteA(A: Double);
begin
  FSeiteA:=A;
end;

procedure TDreieck.SetSeiteB(B: Double);
begin
  FSeiteB:=B;
end;

end.
und die Form:
Delphi-Quellcode:
unit uMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, uBerechnung, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    btnEnde: TButton;
    edtSeiteA: TEdit;
    edtSeiteB: TEdit;
    lblSeiteA: TLabel;
    lblSeiteB: TLabel;
    lblErg: TLabel;
    btnFl: TButton;
    btnDreieck: TButton;
    procedure btnEndeClick(Sender: TObject);
    procedure btnFlClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btnDreieckClick(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btnDreieckClick(Sender: TObject);
var MyFigure: TDreieck;
begin
  MyFigure := TDreieck.Create;
  try
    MyFigure.SeiteA:=strtofloat(edtSeiteA.text);
    MyFigure.SeiteB:=strtofloat(edtSeiteB.text);
    lblErg.caption:=floattostr(MyFigure.BerechneFl)
  finally
    MyFigure.Free;
  end;
end;

procedure TForm1.btnEndeClick(Sender: TObject);
begin
  close;
end;

procedure TForm1.btnFlClick(Sender: TObject);
var MyFigure : TRechteck;
begin
  MyFigure := TRechteck.Create;
  try
    MyFigure.SeiteA:=strtofloat(edtSeiteA.text);
    MyFigure.SeiteB:=strtofloat(edtSeiteB.text);
    lblErg.caption:=floattostr(MyFigure.BerechneFl);
  finally
    MyFigure.Free;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  edtSeiteA.text:='';
  edtSeiteB.text:='';
end;

end.

DeddyH 19. Nov 2017 17:07

AW: Übung Polymorphie
 
Deklariere Deine lokalen Variablen in den Form-Methoden einmal als TFigur. Wenn der Code dann funktioniert, ist das Polymorphie (etwas vereinfacht, aber im Kern richtig).

EdAdvokat 19. Nov 2017 17:39

AW: Übung Polymorphie
 
nachdem ich in der class TFigur eine Ergänzung vorgenommen habe und dann in der Form die lokale Var in TFigur umbenannt habe geht es auch.
Zuvor hatte das Programm jedoch auch keine Probleme.
Delphi-Quellcode:
type TFigur = class(TObject)
  private
    FSeiteA:Double;
    FSeiteB:Double;
    procedure SetSeiteA(A:Double);virtual;abstract;
    procedure SetSeiteB(B:Double);virtual;abstract;

    function getSeiteA:Double;virtual;abstract;
    function getSeiteB:Double;virtual;abstract;
    function getBerechneFl:Double;virtual;abstract;
  public
    property SeiteA:Double read FSeiteA write FSeiteA;
    property SeiteB:Double read FSeiteB write FSeiteB;
    property BerechneFl:Double read getBerechneFl;
Danke.
Also habe ich das Problem wohl richtig verstanden?!

DeddyH 19. Nov 2017 18:12

AW: Übung Polymorphie
 
Ich würde die virtuellen Methoden als protected deklarieren, sonst gibt es Kummer, wenn Du die Ableitungen einmal in eine eigene Unit verschiebst. Und Polymorphie bedeutet ja Vielgestaltigkeit, d.h. der konsumierende Code muss die konkrete Klasse, die er benutzt, gar nicht kennen. Es genügt, wenn er die Basisklasse kennt, ihn interessiert es dabei dann nicht mehr, um welche Ableitung es sich handelt.

EdAdvokat 19. Nov 2017 18:25

AW: Übung Polymorphie
 
habe den Hinweis berücksichtigt, jedoch erhalte ich den folgenden Hinweis:
Zitat:

[dcc32 Hinweis] uBerechnung.pas(25): H2269 Durch das Überschreiben erhält die virtuelle Methode 'TRechteck.SetSeiteA' eine geringere Sichtbarkeit (private) als die Basisklasse 'TFigur' (protected)
Damit kann man sicher leben.

Aviator 19. Nov 2017 18:44

AW: Übung Polymorphie
 
Schreibe den Setter ebenfalls in den Protected Abschnitt und dann ist auch die Warnung weg. Warnungen solltest du schon beachten und auch entsprechend versuchen sie zu beheben. Nicht einfach damit leben. :cyclops:

EdAdvokat 19. Nov 2017 18:55

AW: Übung Polymorphie
 
Ok. Setter ist auch protected. Nun habe ich immer noch eine Warnung:
Zitat:

[dcc32 Warnung] uBerechnung.pas(44): W1045 Eigenschaftsdeklaration verweist auf private-Vorfahr 'TFigur.FSeiteA'
FSeiteA und FSeiteB, die ebenfalls diese Warnung erhält habe ich nur in der class TFigur declariert. Sollte ich diese beiden Felder jeweils auch in die abgeleiteten class aufnehmen als private?

hoika 20. Nov 2017 08:56

AW: Übung Polymorphie
 
Hallo,
nein, dann wären die ja in der Basisklasse überflüssig.
Ich würde den Tip von DeddyH einfach wieder zurücknehmen oder deine privat-Variablen landen
auch in der Basisklasse unter protected.

Das wäre dann zwar ein schönes Beispiel für Polymorphie, aber nicht für Klassendesign.
Dort sollten ja Variablen, die die abgeleitete Klasse nicht zu interessieren hat, privat sein.

DeddyH 20. Nov 2017 09:47

AW: Übung Polymorphie
 
Ich habe das Ganze mal umgeschrieben:
Delphi-Quellcode:
type
  TFigur = class
  private
    FSeiteB: Double;
    FSeiteA: Double;
  protected
    function GetFlaeche: double; virtual; abstract;
  public
    property SeiteA: Double read FSeiteA write FSeiteA;
    property SeiteB: Double read FSeiteB write FSeiteB;
    property Flaeche: double read GetFlaeche;
  end;

  TRechteck = class(TFigur)
  protected
    function GetFlaeche: double; override;
  end;

  TDreieck = class(TRechteck)
  protected
    function GetFlaeche: double; override;
  end;

...

{ TRechteck }

function TRechteck.GetFlaeche: double;
begin
  Result := SeiteA * SeiteB;
end;

{ TDreieck }

function TDreieck.GetFlaeche: double;
begin
  Result := SeiteA * SeiteB / 2;
end;
Formular:
Delphi-Quellcode:
type
  TForm6 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private-Deklarationen }
    procedure ShowFlaeche(Figur: TFigur);
  public
    { Public-Deklarationen }
  end;

...

procedure TForm6.Button1Click(Sender: TObject);
var
  Figur: TFigur;
begin
  Figur := TRechteck.Create;
  try
    Figur.SeiteA := 4;
    Figur.SeiteB := 5;
    ShowFlaeche(Figur);
  finally
    Figur.Free;
  end;
end;

procedure TForm6.Button2Click(Sender: TObject);
var
  Figur: TFigur;
begin
  Figur := TDreieck.Create;
  try
    Figur.SeiteA := 4;
    Figur.SeiteB := 5;
    ShowFlaeche(Figur);
  finally
    Figur.Free;
  end;
end;

procedure TForm6.ShowFlaeche(Figur: TFigur);
begin
  ShowMessage(Format('Die Fläche beträgt %.2f', [Figur.Flaeche]));
end;

freimatz 20. Nov 2017 10:08

AW: Übung Polymorphie
 
Von mir:
- in unit uBerechnung kein uses Vcl.Dialogs
- statt "privat" besser "strict privat" und "strict" auch bei "protected"


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