Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Interface richtig verstanden? (https://www.delphipraxis.net/200576-interface-richtig-verstanden.html)

EdAdvokat 3. Mai 2019 16:43

Interface richtig verstanden?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo zusammen,
ich habe mich etwas mit dem Thema Interface beschäftigt und daraus entstand ein kleines Übungsbeispiel, um zu überprüfen ob ich das Thema
Interface im Ansatz verstanden habe.
Bitte schaut doch mal darüber. Für Hinweise und Korrekturen bin ich dankbar. Sollte es ok sein, wäre meine Freude fast grenzenlos.
Ich will die Sache aber später noch weiterführen.
Danke

Rollo62 3. Mai 2019 16:54

AW: Interface richtig verstanden?
 
Mal schnell im Notepad drübergesehen, sieht doch erstmal ganz OK aus.

Die Tutorials hier und hier kennst du ?

EdAdvokat 3. Mai 2019 17:33

AW: Interface richtig verstanden?
 
ich will meine Frage erweitern: Wenn ich also ein Basisobjekt
Delphi-Quellcode:
type
  TFigure = class(TInterfacedObject, IFigur)
   FSeiteA : Double;
   FSeiteB : Double;
   function Umfang: Double;
   function Flaecheninhalt: Double;
 end;
nach der Dekleration des Interface erstelle und davon dann die weiteren Figuren (Quadrat, Dreieck usw) ableite, wird dann auch das TInterfacedObject vererbt,
dass für die Speicherfreigabe verantwortlich ist?
Kann ich also mit
Delphi-Quellcode:
 type
 TQuadrat = class (TFigure, IFigur)
  FSeiteA : double;              
  FSeiteB : double;
  function Umfang:double;
  function Flaecheninhalt:double;
 end;
weitere Klassen vererben, die dann auch TInterfacedObject erhalten?

Der schöne Günther 3. Mai 2019 17:44

AW: Interface richtig verstanden?
 
Die Antwort auf deine Frage ist "Ja":
  • TFigure ist ein TInterfacedObject
  • TQuadrat ist ein TFigure, folglich ist es auch ein TInterfacedObject und bringt alles mit (wie z.B. Interface-Unterstützung)

Aber:
  1. Du deklarierst die Felder "FSeiteA" und "FSeiteB" einmal in TFigure, und dann noch einmal in "TQuadrat".
  2. Mit den Methoden verhält es sich ähnlich: Dass die Methoden in "TFigure" nicht
    Delphi-Quellcode:
    virtual
    sind ist eigentlich ein Fehler. Hast du das mit virtuellen Methoden ("Polymorphie") verstanden? Du brauchst keine Interfaces für Polymorphie, aber umgekehrt muss man das verstanden haben bevor man sich an Interfaces wagt
  3. Sicher ist es nur ein Beispiel, aber mit der Klasse TFigure hast du eigentlich nichts gewonnen. Wie würdest du denn
    Delphi-Quellcode:
    Umfang()
    oder
    Delphi-Quellcode:
    Flächeninhalt()
    allgemeingültig implementieren wollen? Die Klasse an sich ist völlig abstrakt. Um das zu signalisieren kannst du z.B. statt
    Delphi-Quellcode:
    TFigure = class(TInterfacedObject, IFigur)
    auch schreiben
    Delphi-Quellcode:
    TFigure = class abstract(TInterfacedObject, IFigur)
    . Damit bekämst du auch eine Compiler-Warnung wenn du eine TFigure statt z.B. einem TQuadrat erstellst, denn ein TFigure ist nur eine abstrakte Vorlage.

EdAdvokat 3. Mai 2019 18:14

AW: Interface richtig verstanden?
 
Danke
zum ersten Punkt: Das habe ich bereits selbst erkannt und verändert. Wenn FSeiteA und FSeiteB im Basisobject deklariert sind, müssen sie nicht nochmals im abgeleiteten Objekt aufgeführt werden.
Punkt 2 habe ich noch nicht so richtig verstanden. Sicher gibt es keine allgemeingültige Formel für Umfang und Flächeninhalt versch. Figuren.
Diese habe ich jedoch dann in den jeweiligen Klassen konkret umgesetzt und wie ich glaube, funktioniert das auch exakt.
Punkt 3 habe ich befolgt und
Delphi-Quellcode:
TFigure = class abstract(TInterfacedObject, IFigur)
eingefügt.

Der schöne Günther 3. Mai 2019 18:56

AW: Interface richtig verstanden?
 
zu Punkt 2:

Richtig, es gibt keine allgemeingültige Formel. Die in den entsprechenden Klassen dann umzusetzen ist völlig richtig.
Ohne die Schlüsselwörter "virtual" und "override" gibt es allerdings ein Problem - Wenn du eine Variable vom Typ IFigur hast weiß er nicht dass die wirkliche Bestimmung der Fläche nicht in der Klasse (TFigure) sondern in einer Unterklasse steckt.

Ich habe hier einmal ein kurzes Komplettbeispiel gemacht, allerdings mit Tieren statt Formen 😉

https://gist.github.com/JensMertelme...509caa07a057a6

Rollo62 4. Mai 2019 07:57

AW: Interface richtig verstanden?
 
Das Interface ist ein Vertrag welche Funktionen dein Objekt haben soll.
Das kann mit oder ohne Vererbung sein.
Ja nachdem worum es geht kann Beides sinnvoll sein.

Bei Figuren wäre das virtuelle Ableiten wirklich sinnvoller, damit die Basisklasse gemeinsame Figuren-aufgaben übernehmen kann, ohne in den abgeleiteten Klassen das zu wiederholen.
Die virtuellen Funktion können dann aber bei Bedarf die Basisfunktionen überschreiben,
wenn es notwendig ist.
Z.B. ein Polyeder wäre nur mit x,y nicht mehr abbildbar, und müsste deshalb intern anders aufgebaut sein.

Der Vertrag zum Abfragen Fläche bleibt aber trotzdem gleich.

EdAdvokat 4. Mai 2019 10:14

AW: Interface richtig verstanden?
 
Danke für eure Hinweise. Ich habe es also etwas verändert und es läuft gut. Nun möchte ich noch etwas tiefer in die Problematik Interface einsteigen.
Delphi-Quellcode:
unit logic;

interface

uses Vcl.Dialogs;

Type
IFigur = interface
 ['{921A6F17-0D63-40EC-82FD-F60CB5F66DC3}']
   function Umfang:double;
   Function Flaecheninhalt:double;
end;

type
  TFigure = class abstract(TInterfacedObject, IFigur)//Basis_Class
  private
   FSeiteA : Double;
   FSeiteB : Double;
  strict protected
   function Umfang: Double;virtual;
   function Flaecheninhalt: Double;virtual;
  public
    property SeiteA: Double read FSeiteA write FSeiteA;
    property SeiteB: Double read FSeiteA write FSeiteB;
 end;

type
 TQuadrat = class (TFigure, IFigur) //class Decleration mit Hinweis auf IFigur
  strict protected          //TInterfacedObject übernimmt die Freigabe d. Objects
    function Umfang:double;override;
    function Flaecheninhalt:Double;override;
  public
    property Umfangber: Double read Umfang;
    property Flaechenber: Double read Flaecheninhalt;
 end;

type
 TDreieck = class(TFigure, IFigur)
  private
   FSeiteC : double;
   FHoehe : Double;
  strict protected
   function Umfang:double;override;
   function Flaecheninhalt:double;override;
  public
   property SeiteC: Double read FSeiteC write FSeiteC;
   property Hoehe: Double read FHoehe write FHoehe;
   property Umfangber: Double read Umfang;
   property Flaechenber: Double read Flaecheninhalt;
 end;

type
 TTrapez = class(TFigure, IFigur)
  private
   FSeiteC : Double;
   FSeiteD : Double;
   FHoehe : double;
  strict protected
   function Umfang:double;override;
   function Flaecheninhalt:double;override;
  public
    property SeiteC: Double read FSeiteC write FSeiteC;
    property SeiteD: Double read FSeiteD write FSeiteD;
    property Hoehe: Double read FHoehe write FHoehe;
    property Umfangber: Double read Umfang;
    property Flaechenber: Double read Flaecheninhalt;
 end;

implementation

  { TQuadrat }

function TQuadrat.Flaecheninhalt: double;
begin
  Result:=FseiteA*FSeiteB;
end;

function TQuadrat.Umfang: double;
begin
  Result:=2*FseiteA+2*FseiteB;
end;

{ TDreieck }

function TDreieck.Flaecheninhalt: double;
begin
 Result:=FSeiteA*FSeiteB/2;
end;

function TDreieck.Umfang: double;
begin
   Result:=FSeiteA+FSeiteB+FSeiteC;
end;

 { TTrapez }

function TTrapez.Flaecheninhalt: Double;
begin
  result:=(FSeiteA+FSeiteC)/2*FHoehe;
end;

function TTrapez.Umfang: Double;
begin
  Result:=FSeiteA+FSeiteB+FSeiteC+FSeiteD;
end;

{ TFigure }

function TFigure.Flaecheninhalt: Double;
begin
  Result:=Flaecheninhalt;
end;

function TFigure.Umfang: Double;
begin
  Result:=Umfang;
end;

end.
und das MainForm:
Delphi-Quellcode:
unit uMain;

interface

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

type
  TForm1 = class(TForm)
    lbl1: TLabel;
    btn1: TButton;
    edt1: TEdit;
    btn2: TButton;
    edt2: TEdit;
    lbl2: TLabel;
    lbl3: TLabel;
    btn3: TButton;
    edt3: TEdit;
    lbl4: TLabel;
    lbl5: TLabel;
    lbl6: TLabel;
    lbl7: TLabel;
    btn4: TButton;
    lbl9: TLabel;
    edt4: TEdit;
    edt5: TEdit;
    lbl10: TLabel;
    lbl11: TLabel;
    procedure btn1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btn2Click(Sender: TObject);
    procedure btn3Click(Sender: TObject);
    procedure btn4Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btn1Click(Sender: TObject);
begin
  Close;
end;

procedure TForm1.btn2Click(Sender: TObject);
var MyFigure: TQuadrat;
begin
  MyFigure:=TQuadrat.Create; //Freigabe nicht erf., da TInterfacedObject dies übernimmt
  try
  MyFigure.SeiteA:=strtoint(edt1.Text);
  MyFigure.SeiteB:=StrToInt(edt2.text);
  lbl2.Caption:=FloatToStr(MyFigure.Umfangber);
  lbl3.Caption:=FloatToStr(MyFigure.Flaechenber);
  except
    on E:Exception do
    begin
       ShowMessage('Exception class name = '+E.ClassName);
       ShowMessage('Exception message = '+E.Message);
    end;
  end;
end;

procedure TForm1.btn3Click(Sender: TObject);
var MyFigure: TDreieck;
begin
  MyFigure:=TDreieck.Create;
  try
  MyFigure.SeiteA:=StrToFloat(edt1.Text);
  MyFigure.SeiteB:=StrToFloat(edt2.text);
  MyFigure.SeiteC:=StrToFloat(edt4.text);
  lbl2.Caption:=FloatToStr(MyFigure.Umfangber);
  lbl3.Caption:=FloatToStr(MyFigure.Flaechenber);
  except
    on E:Exception do
    begin
       ShowMessage('Exception class name = '+E.ClassName);
       ShowMessage('Exception message = '+E.Message);
    end;
  end;
end;

procedure TForm1.btn4Click(Sender: TObject);
var MyFigure: TTrapez;
begin
  MyFigure:=TTrapez.Create;
  try
  MyFigure.SeiteA:=StrToFloat(edt1.Text);
  MyFigure.SeiteB:=StrToFloat(edt2.text);
  MyFigure.Hoehe:=StrToFloat(edt3.text);
  MyFigure.SeiteC:=StrtoFloat(edt4.Text);
  MyFigure.SeiteD:=StrtoFloat(edt5.Text);
  lbl2.Caption:=FloatToStr(MyFigure.Umfangber);
  lbl3.Caption:=FloatToStr(MyFigure.Flaechenber);
  except
    on E:Exception do
    begin
       ShowMessage('Exception class name = '+E.ClassName);
       ShowMessage('Exception message = '+E.Message);
    end;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  edt1.Clear;
  edt2.Clear;
  edt3.Clear;
  edt4.Clear;
  edt5.Clear;
  lbl2.Caption:='';
  lbl3.Caption:='';
end;

end.

Rudy Velthuis 4. Mai 2019 15:10

AW: Interface richtig verstanden?
 
Zitat:

Zitat von EdAdvokat (Beitrag 1431546)
Nun möchte ich noch etwas tiefer in die Problematik Interface einsteigen.

Interfaces sind keine Problematik, sie sind eine Lösung. :wink:

EdAdvokat 4. Mai 2019 16:15

AW: Interface richtig verstanden?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo zusammen,
nun habe ich mit meiner Drohung ernst gemacht und biete eine neue "Lösung" der Problematik (!) Interface an.
Um nicht auch eines Plagiats verdächtig zu sein verweise ich auf eine 3-teilige Videoaufzeichnung von StahliSoft in seinem Youtubekanal zu diesem Thema.
Ich habe diese Videos aufmerksam verfolgt und mit dem beiliegenden Projekt nachempfunden. Ich danke dem Euch sicher aus dem hiesigen Formum und seinen
anderen Veröffentlichungen bekannten A. Stahl ganz herzlich für das sehr unaufgeregt und verständlich dargestellte Video zu einem doch nicht ganz einfachen Thema.
Ich hoffe, dass ich alles richtig gemacht habe. Jedenfalls läuft es bei mir ohne erkenntliche Fehler.

stahli 4. Mai 2019 18:48

AW: Interface richtig verstanden?
 
Oh, zu viel der Ehre. :oops: Aber Danke.

In Deinem Projekt sind mir beim schnellen drauf schauen ein paar Dinge aufgefallen:

- OnCreate wird nicht aufgerufen. Die Ereignisbehandlung ist nicht richtig zugewiesen. (Musst Du mal zuweisen und einen Haltepunkt setzen.)
- Die Methoden Fahr und Flieg und Schwimm rufen sich selbst auf. Das führt zu einem Stack Overflow.
- Deine Klassen leitest Du manchmal von TInterfacedObject ab und manchmal von einer eigenen Basisklasse. Das ist nicht falsch, aber man muss sich immer genau überlegen, von was man ableitet, damit das dann zur Geschäftslogik passt.
- Supports kann noch mehr. Man kann eine eigene Variable dafür benutzen. Ich mache gern das so weil es m.E. übersichtlicher ist:
Delphi-Quellcode:
var
  lSchwimm: ISchwimm;

  if Supports(I, ISchwimm, lSchwimm) then
    lSchwimm.Schwimm;

Ich hoffe, das hilft noch etwas weiter...

Rudy Velthuis 4. Mai 2019 19:11

AW: Interface richtig verstanden?
 
Zitat:

Zitat von stahli (Beitrag 1431567)
Delphi-Quellcode:
var
  lSchwimm: ISchwimm;

Echt jetzt, lSchwimm und ISchwimm? Die sind ja kaum auseinander zu halten!

Dann schreibe doch wenigstens LSchwimm. Das ist besser lesbar.

stahli 4. Mai 2019 19:17

AW: Interface richtig verstanden?
 
"l" für lokal
Ich komme damit klar.

Dennis07 4. Mai 2019 19:29

AW: Interface richtig verstanden?
 
Zitat:

Zitat von stahli (Beitrag 1431570)
"l" für lokal
Ich komme damit klar.

Mag sein, ist aber weder besonders zweckmäßig, noch konform mit den allgemeinen Style-Guidelines.

Rudy Velthuis 4. Mai 2019 19:57

AW: Interface richtig verstanden?
 
Zitat:

Zitat von stahli (Beitrag 1431570)
"l" für lokal
Ich komme damit klar.

"L" wäre auch für lokal und lesbar.

Und man schreibt nicht nur für sich selbst. Code sollte lesbar sein, damit auch andere ihn lesen können (oder du selbst, z.B. nach 6 Monaten).
Vor allem Code, den du ausdrücklich für andere schreibst (wie hier).

"Ich komme damit klar" ist sowas wie "auf meinem Rechner läuft's".

EdAdvokat 4. Mai 2019 20:11

AW: Interface richtig verstanden?
 
Hinweise 1-3 aus #11 habe ich abgeändert.
Den letzten Stabstrich verstehe ich nicht:
Zitat:

- Supports kann noch mehr. Man kann eine eigene Variable dafür benutzen. Ich mache gern das so weil es m.E. übersichtlicher ist:
markieren
Delphi-Quellcode:
var
  lSchwimm: ISchwimm;

  if Supports(I, ISchwimm, lSchwimm) then
    lSchwimm.Schwimm;
Sicher muss ich auch noch nicht alles verstehen, doch die ganze Sache hat mich in Fragen Interfaces doch ein kleines Stück weiter gebracht.
Nochmals Danke an alle Mitwirkenden

stahli 4. Mai 2019 21:01

AW: Interface richtig verstanden?
 
Supports weist einfach das Ergebnis gleich der Variablen zu, mehr ist da gar nicht... (also intern wird sowas wie
Delphi-Quellcode:
lSchwimm := (I as ISchwimm)
gemacht)
Wenn Support False liefert, enthält die Variable NIL.

Das macht die Verwendung von Supports etwas übersichtlicher.

TurboMagic 5. Mai 2019 08:43

AW: Interface richtig verstanden?
 
Zitat:

Zitat von stahli (Beitrag 1431570)
"l" für lokal
Ich komme damit klar.

Das mag sein, aber hier muss ich mal doch Rudy zustimmen! ;-)
Man kann da sehr leicht was verwechseln...

Schokohase 5. Mai 2019 09:06

AW: Interface richtig verstanden?
 
Damit es auch jeder versteht:

Das Problem ist, dass Klein-Ludwig fast genauso aussieht wie Groß-Ida. Ja es ist abhängig vom Font.
Zitat:

l vs I
Zumal man im Allgemeinen in Delphi die PascalCase Schreibweise für Variablen-Namen bevorzugt und nicht wie z.B. bei C# camelCase. Und bei PascalCase wird der erste Buchstabe immer groß geschrieben.

Warum das jetzt wohl PascalCase heißt und wo das historisch herkommt darüber darf ein jeder still vor sich hin sinnieren.

Das Problem ist also nicht das L sondern nur die Schreibweise als Kleinbuchstabe.

EdAdvokat 5. Mai 2019 10:01

AW: Interface richtig verstanden?
 
Ich komme nochmals auf das Projekt von Stahli zurück.
TVogel hat das Interface IFlieg und die diesem eigene procedure Flieg.
TStorch wurde von TVogel abgeleitet. Also sollte doch auch TStorch, ebenso wie TAdler auch die das Interface IFlieg
besitzen, doch weder TStorch noch TAdler haben die von IFlieg verlangte procedure Flieg.
Bisher bin ich davon ausgegangen, dass die abgeleiteten Klassen (TStorch und TAdler) sowohl die Eigenschaften der
Basisklasse (TVogel) als auch das dem TVogel zugeordnete Interfache IFlieg ebenso wie das TInterfacedObject erben.
Hab ich das ganze noch nicht richtig verstanden?

Schokohase 5. Mai 2019 10:11

AW: Interface richtig verstanden?
 
Wenn
Delphi-Quellcode:
TVogel
das Interface
Delphi-Quellcode:
IFlieg
implementiert, dann muss es dort auch alle Interface-Methoden geben.

Und wenn es diese gibt, dann sind die auch noch da, wenn ich von
Delphi-Quellcode:
TVogel
ableite. Das ist wie beim Vererben von Klassen, weil es Vererben von Klassen ist und hat mit Interfaces gar nichts zu tun.

EdAdvokat 5. Mai 2019 10:19

AW: Interface richtig verstanden?
 
Zitat:

Zitat von Schokohase (Beitrag 1431588)
Wenn
Delphi-Quellcode:
TVogel
das Interface
Delphi-Quellcode:
IFlieg
implementiert, dann muss es dort auch alle Interface-Methoden geben.

Und wenn es diese gibt, dann sind die auch noch da, wenn ich von
Delphi-Quellcode:
TVogel
ableite. Das ist wie beim Vererben von Klassen, weil es Vererben von Klassen ist und hat mit Interfaces gar nichts zu tun.

So ist auch mein Verständnis, jedoch die Tatsache, dass weder TAdler noch TStorch die der von IFlieg verlangten procedure Flieg haben, irritiert mich.Zusammengefasst: Warum läßt sich TAdler und TStorch ohne die procedure flieg erstellen? Wenn ich bei TVogel die procedure flieg auskommentiere, meckert der Compiler zu recht. Bei den abgeleiteten und mit allen Merkmalen der Vorfahren ausgestatteten TStorch und TAdler geht es ohne procedure flieg.

Schokohase 5. Mai 2019 10:24

AW: Interface richtig verstanden?
 
Wenn TVogel die Methode Flieg hat und leite von TVogel jetzt TStorch ab, dann erbt TStorch auch die Methode Flieg.

Das nennt man Vererbung!
Delphi-Quellcode:
TVogel = class
public
  procedure Flieg();
end;

TStorch = class(TVogel)
end;

procedure Foo();
var
  LStorch: TStorch;
begin
  LStorch := TStorch.Create();
  LStorch.Flieg(); // geht, weil von TVogel geerbt
end;
Du bist dir sicher, dass du ohne diese grundlegenden OOP Kenntnisse weiter in OOP mit Interfaces einsteigen willst?

stahli 5. Mai 2019 10:31

AW: Interface richtig verstanden?
 
Doch, das funktioniert auch.
Ersetze mal FormCreate (und die Unit u_Voegel musst Du natürlich noch einbinden).
Dann siehst Du, dass Storch.Flieg und auch IFlieg unterstützt wird.
Da musst Du irgend einen anderen Fehler drin haben.
Durch die Vererbung kennt die neue Klasse auch alles, was die Basisklasse kennt.
(Wenn man dann Methoden überschreiben will, muss man mit virtual und override arbeiten.)

Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
var
  R: IReader;
  S: ISchwimm;
  I: IInterface;
  //TList<ISchwimm>
  Storch: TStorch;
begin
  R := TXMLReader.Create;
  Read(R);
  R := TCSVReader.Create;
  Read(R);
//
//  S := TFactory.GetNewEnte;
//  S.Schwimm;
//  S := TFactory.GetNewBoot;
//  S.Schwimm;

  I := TFactory.GetNewEnte;
  if Supports(I, ISchwimm) then
    (I as ISchwimm).Schwimm;

  I := TFactory.GetNewAdler;
  if Supports(I, ISchwimm) then
    (I as ISchwimm).Schwimm;

  I := TFactory.GetNewEnte;
  if Supports(I, ISchwimm) then
    (I as ISchwimm).Schwimm;

  I := TFactory.GetNewAdler;
  if Supports(I, IFlieg) then
    (I as IFlieg).Flieg;

  I := TFactory.GetNewEnte;
  if Supports(I, IFlieg) then
    (I as IFlieg).Flieg;

  Storch := TStorch.Create;
  Storch.Flieg;
  if Supports(Storch, IFlieg) then
    ShowMessage('Flieg');

end;


Zusätzliche Anmerkung:

Etwas komplizierter wird es bei Vererbungen von Interfaces.
Wenn man ein InterfaceA hat und davon InterfaceB ableitet, und dann eine Klasse deklariert:
class TX(TInterfacedObject, InterfaceB),
dann liefert Supports(X, InterfaceA) false.

Um ein Supports zu ermöglichen, muss man das der Klasse AUSDRÜCKLICH zuweisen:
class TX(TInterfacedObject, InterfaceB, InterfaceA)

EdAdvokat 5. Mai 2019 10:34

AW: Interface richtig verstanden?
 
Delphi-Quellcode:
type

  TVogel = class(TInterfacedObject, IFlieg)
  private
  public
    procedure Flieg;
  end;

  TStorch = class(TVogel)
  private
    FSchnabellaenge: Integer;
    procedure SetSchnabellaenge(const Value: Integer);
  public
    property Schnabellaenge: Integer read FSchnabellaenge write SetSchnabellaenge;
  end;

  TAdler = class(TVogel)
  private
    FDioptrien: Integer;
    procedure SetDioptrien(const Value: Integer);
  public
    property Dioptrien: Integer read FDioptrien write SetDioptrien;
  end;

  TEnte = class(TVogel, ISchwimm)
  private
    FKalorien: Integer;
    procedure SetKalorien(const Value: Integer);
    procedure Schwimm;
  public
    property Kalorien: Integer read FKalorien write SetKalorien;
  end;

implementation

{ TStorch }

procedure TStorch.SetSchnabellaenge(const Value: Integer);
begin
  FSchnabellaenge := Value;
end;

{ TAdler }

procedure TAdler.SetDioptrien(const Value: Integer);
begin
  FDioptrien := Value;
end;

{ TEnte }

procedure TEnte.Schwimm;
begin

end;

procedure TEnte.SetKalorien(const Value: Integer);
begin

end;

{ TVogel }

procedure TVogel.Flieg;
begin

end;

end.
also weil ich die procedure Flieg bereits bei TVogel (ganz unten) erstellt habe, ist sie damit auch Bestandteil von TAdler und TStorch, ohne dass ich sie dort nochmals erstellen muss.

Schokohase 5. Mai 2019 10:35

AW: Interface richtig verstanden?
 
Das ist Vererbung und ist ein essentieller Teil von OOP

BTW Warum leitest du von
Delphi-Quellcode:
TInterfacedObject
ab? Weil du die dort implementierten Funktionen verwenden möchtest? Aber nach deinem Verständnis passiert das doch nicht.

EdAdvokat 5. Mai 2019 10:50

AW: Interface richtig verstanden?
 
ich denke doch dass ich die Vererbung in OOP verstehe. Doch die Forderung bei Interface stets die in der Interface-Dekleration aufgeführten Methoden in den Klassen, die
dieses Interface verwenden auch explizit aufzuführen, hat mich verwirrt.
Also da TVogel bereits die procedure flieg hat, kann ich TAdler und TStorch auch fliegen lassen, obwohl im vorliegenden Fall mit keinem Hinweis bei TAdler auf die procedure Flieg
eingegangen wird.
Entschuldigung für meinen gedanklichen Klemmer.:oops:

stahli 5. Mai 2019 11:04

AW: Interface richtig verstanden?
 
Kein Problem. :-)
Kindklassen erben einfach auch Interfaces mit.

EdAdvokat 5. Mai 2019 11:40

AW: Interface richtig verstanden?
 
Stahli, Danke mit Deinem Beitrag #24 hast Du den konkreten Nachweis erbracht dass der Storch wirklich fliegt (showMessage('flieg').
Entschuldigung, es tut mir leid, euch genervt zu haben, doch manchmal hat man einen Klemmer.

Rollo62 6. Mai 2019 06:56

AW: Interface richtig verstanden?
 
Mit Interfaces kann man aber noch viel mehr Unsinn anstellen.
Weiterführende Beispiele z.B. hier.

exilant 6. Mai 2019 08:25

AW: Interface richtig verstanden?
 
Zitat:

Zitat von Rudy Velthuis (Beitrag 1431559)
Zitat:

Zitat von EdAdvokat (Beitrag 1431546)
Nun möchte ich noch etwas tiefer in die Problematik Interface einsteigen.

Interfaces sind keine Problematik, sie sind eine Lösung. :wink:

Zum Glück meistens nicht die einzige Lösung. Und auch längst nicht immer die beste. [...duck und weg]

generic 9. Mai 2019 06:58

AW: Interface richtig verstanden?
 
Schaut euch doch mal das Buch

Head First: Design Patterns
von Eric Freeman

an.

Da wird mit Enten auf Interfaces hin geleitet.
Tolle Beispiele.

Werbelink zu Amazon: https://amzn.to/2LxZLgz


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