![]() |
Tutorial Interfaces
Liste der Anhänge anzeigen (Anzahl: 1)
Tutorial Interfaces
Warum dieses Tutorial? Es ist mir aufgefallen das immer wieder Missversändnisse und Unklarheiten über den Nutzen und Einsatz von Interfaces auftreten. Deshalb habe ich mich Entschlossen das etwas aufzuhellen. Dieses Tutorial beinhaltet natürlich meine Sicht darauf und ich lasse mich gerne verbessern. Was ist ein Interface? Ein Interface, übersetzt Schnittstelle, ist genau das was der Name uns mitteilt, es ist eine Schnittstelle zwischen verschiedenen Programmteilen. Der Vorteil liegt in der Trennung von Definition und Implementation. Ein CodeTeil der eine Schnittstelle benutzt muss nicht wissen wie diese Umgesetzt (Implementiert) ist. Betrachten wir es wie eine USB Verbindung. Wir haben das Interface (den Stecker, die Buchse) und da können die verschiedensten Geräte verbunden werden. Alles was jedes Ende wissen muss, ist wie über die Schnittstelle (Interface) kommuniziert wird. Ob da nun ein Drucker, eine Kamera oder was auch immer daran hängt ist erst einmal unwichtig. In diesem Tutorial gehe ich erst einmal auf eine recht einfache Anwendung von Interfaces ein. Ich denke jeder kennt das Problem: Programmeinstellungen, Anwendereinstellunge etc. müssen zwischengespeichert werden, damit der Anwender seine Einstellungen etc. bei jedem Programmstart wieder findet. Die Lösung die fast jeder da gerne zumindest am Anfang verwendet sind Inifiles. Einfach zu benutzen und effektiv. Irgendwann dann sollen die Einstellungen in eine Datenbank oder ähnliches geschrieben werden. Es steht ein grösserer Umbau an. Die Lösung? Ja genau Interfaces! Das TCustomIniFile hat eigentlich schon alles was wir brauchen. Wir könnten einfach ein neue Klasse ableiten und diese benutzen. Einfacher wird es aber wenn wir daraus den benötigten Teil in ein Interface auslagern und in unseren CodeTeilen dieses benutzen. Das sieht dann z.B so aus:
Delphi-Quellcode:
Anstatt einer Methode unserer Klassen mit der Signatur
iConfigReadWriter = interface
['{AE9CC6E5-F0B8-4D39-8F6C-799423C60A37}'] function SectionExists(const Section: string): Boolean; function ReadString(const Section, Ident, Default: string): string; procedure WriteString(const Section, Ident, Value: string); function ReadInteger(const Section, Ident: string; Default: Longint): Longint; procedure WriteInteger(const Section, Ident: string; Value: Longint); function ReadBool(const Section, Ident: string; Default: Boolean): Boolean; procedure WriteBool(const Section, Ident: string; Value: Boolean); function ReadBinaryStream(const Section, Name: string; Value: TStream): Integer; function ReadDate(const Section, Name: string; Default: TDateTime): TDateTime; function ReadDateTime(const Section, Name: string; Default: TDateTime): TDateTime; function ReadFloat(const Section, Name: string; Default: Double): Double; function ReadTime(const Section, Name: string; Default: TDateTime): TDateTime; procedure WriteBinaryStream(const Section, Name: string; Value: TStream); procedure WriteDate(const Section, Name: string; Value: TDateTime); procedure WriteDateTime(const Section, Name: string; Value: TDateTime); procedure WriteFloat(const Section, Name: string; Value: Double); procedure WriteTime(const Section, Name: string; Value: TDateTime); procedure ReadSection(const Section: string; Strings: TStrings); procedure ReadSections(Strings: TStrings); overload; procedure ReadSections(const Section: string; Strings: TStrings); overload; procedure ReadSubSections(const Section: string; Strings: TStrings; Recurse: Boolean = False); procedure ReadSectionValues(const Section: string; Strings: TStrings); procedure EraseSection(const Section: string); procedure DeleteKey(const Section, Ident: string); function ValueExists(const Section, Ident: string): Boolean; end;
Delphi-Quellcode:
können wir die Signatur ändern zu
procedure SaveConfig(Value : TcustomIniFile);
Delphi-Quellcode:
procedure SaveConfig(Value : iConfigReadWriter);
für unseren restlichen Code ändert sich nichts da die Signaturen der Methoden gleich sind.
Delphi-Quellcode:
Dies erfordert natürlich das wir die Erzeugung und Freigebe unserer "Schnittstelle" vom eigentlichen Code trennen.
Value.WriteString('DATA','DUMP','Meine Daten');
Also anstatt einer methode:
Delphi-Quellcode:
haben wir zumindest:
procedure tuseini.BadSaveData;
var lini: TCustomIniFile; begin lini := TIniFile.Create('Was auch immer'); try lini.WriteString('Data', 'Dump', 'meine Daten'); // etc finally lini.free; end; end;
Delphi-Quellcode:
procedure tuseini.BetterSaveSettings(Writer: TCustomIniFile);
begin Writer.WriteString('Data', 'Dump', 'meine Daten'); end; procedure tuseini.BetterSaveData; var lini: TCustomIniFile; begin lini := TIniFile.Create('Was auch immer'); try BetterSaveSettings(lini); finally lini.free; end; end; Aus meiner Sicht ist dies die optimale Lösung:
Delphi-Quellcode:
Unser Klasse muss nur das Interface kennen, was dahinter wirklich passiert ist nicht wichtig für die Benutzung.
procedure tuseini.SaveSettings(Writer: iConfigReadWriter);
begin Writer.WriteString('Test', 'Dummy', 'Default'); end; procedure tuseini.ReadSettings(Reader: iConfigReadWriter); begin fmySetting := Reader.ReadString('Test', 'Dummy', 'Empty'); end; Im Testprojekt ist jetzt auch ein Datamodul dass dieses Interface implementiert. Es sind nicht alle Methoden befüllt sollte aber den zeigen wie man so einfach die Implementation ändern kann, ohne in der benutzenden Klasse etwas zu ändern.
Delphi-Quellcode:
TDataModule1 = class(TDataModule, iConfigReadWriter)
FDConnection1: TFDConnection; FDGUIxWaitCursor1: TFDGUIxWaitCursor; FDPhysSQLiteDriverLink1: TFDPhysSQLiteDriverLink; procedure DataModuleDestroy(Sender: TObject); procedure DataModuleCreate(Sender: TObject); private procedure DeleteKey(const Section, Ident: string); procedure EraseSection(const Section: string); function ReadBinaryStream(const Section, Name: string; Value: TStream): Integer; function ReadBool(const Section, Ident: string; Default: Boolean): Boolean; function ReadDate(const Section, Name: string; Default: TDateTime): TDateTime; function ReadDateTime(const Section, Name: string; Default: TDateTime): TDateTime; function ReadFloat(const Section, Name: string; Default: Double): Double; function ReadInteger(const Section, Ident: string; Default: Longint): Longint; procedure ReadSection(const Section: string; Strings: TStrings); procedure ReadSections(const Section: string; Strings: TStrings); overload; procedure ReadSections(Strings: TStrings); overload; procedure ReadSectionValues(const Section: string; Strings: TStrings); function ReadString(const Section, Ident, Default: string): string; procedure ReadSubSections(const Section: string; Strings: TStrings; Recurse: Boolean = False); function ReadTime(const Section, Name: string; Default: TDateTime): TDateTime; function SectionExists(const Section: string): Boolean; function ValueExists(const Section, Ident: string): Boolean; procedure WriteBinaryStream(const Section, Name: string; Value: TStream); procedure WriteBool(const Section, Ident: string; Value: Boolean); procedure WriteDate(const Section, Name: string; Value: TDateTime); procedure WriteDateTime(const Section, Name: string; Value: TDateTime); procedure WriteFloat(const Section, Name: string; Value: Double); procedure WriteInteger(const Section, Ident: string; Value: Longint); procedure WriteString(const Section, Ident, Value: string); procedure WriteTime(const Section, Name: string; Value: TDateTime); { Private-Deklarationen } public { Public-Deklarationen } end; Dies habe ich im testProjekt über eine simple Factory gelöst. Im Anhang findet Ihr ein Projekt das dies Umsetzt. Bei Interesse kann ich auch noch weiter in die Interface problematik einsteigen, Supports, Delegeation etc.. Habe das Tutorial.zip erweitert mit einer DB Lösung |
AW: Tutorial Interfaces
Ich hoffe meine Frage ist eine berechtigte Frage:
worin liegt der Vorteil gegenüber normalen IniFiles in der fertigen ausführbaren Datei? |
AW: Tutorial Interfaces
"Ein Interface, übersetzt Schnittstelle, ist genau das was der Name uns mitteilt, es ist eine Schnittstelle zwischen verschiedenen
Programmteilen. Der Vorteil liegt in der Trennung von Definition und Implementation." Nun, diese Unterscheidung zwischen Deklaration und Implementation wird auch im Unit-Konzept realisiert. Sogar die übergebenen Variablen bei Unterprogrammen erfüllen dieses Schnittstellenkonzept. Mithin ist mir der Vorteil der Interfaces leider nicht klargeworden. |
AW: Tutorial Interfaces
Man muss sich einfach darüber klar sein, dass ein Interface ganz bewusst nichts Konkretes ist, sondern lediglich eine Zusicherung. Das bedeutet, der Benutzer (im Sinne einer Klasse) des Interfaces muss die konkrete Implementation überhaupt nicht kennen, kann sich aber trotzdem sicher sein, dass alle im Interface deklarierten Properties und Methoden vorhanden sind. Dadurch wird eine einfache Erweiterbarkeit erreicht. Ein kleines Beispiel: nehmen wir an, wir haben die Klassen TDings und TConsumer. Letztere ruft eine Methode Blubb der Ersteren auf.
Delphi-Quellcode:
Alles cool, alles easy. Nun wollen wir das Programm erweitern und schreiben eine Klasse TBums, die ebenfalls eine Methode Blubb enthält. Die Consumer-Klasse soll sowohl mit TDings als auch mit TBums umgehen können. Was können wir tun? Mir fallen da ein paar Möglichkeiten ein:
type
TDings = class public procedure Blubb; end; TConsumer = class public procedure Wuppdi(const Dings: TDings); end; ... procedure TConsumer.Wuppdi(const Dings: TDings); begin Dings.Blubb; end; - Überladen der Wuppdi-Methode - Ableiten der TDings- und TBums-Klasse von einer gemeinsamen Elternklasse, die Blubb als (ggf. virtuelle oder dynamische) Methode einführt. Das macht dann eine Änderung des Parametertyps in den Typ der Elternklasse notwendig. - Ändern des Parametertyps in TObject und Abfrage in der Methode, ob es sich um TDings oder TBums handelt, dann Typecast und Aufruf. Das ist alles nicht so wirklich elegant und macht Änderungen an verschiedenen Stellen nötig. Hier kommen jetzt die Interfaces ins Spiel: man ändert einmalig den Parametertyp in einen Interfacetyp, in dem die Blubb-Methode vereinbart wird. TDings und TBums implementieren jetzt dieses Interface, TConsumer greift dann darüber auf die Methode zu. Soll später eine weitere Klasse TSchiessMichTot dazukommen, lässt man sie ebenfalls das Interface implementieren, schon kann TConsumer ohne jede Codeänderung auch damit umgehen.
Delphi-Quellcode:
type
ISuperIntf = interface ['{01107754-046D-4A32-AC6F-D96BC2AECCE0}'] procedure Blubb; end; TDings = class(TInterfacedObject, ISuperIntf) public procedure Blubb; end; TBums = class(TInterfacedObject, ISuperIntf) public procedure Blubb; end; ... procedure TConsumer.Wuppdi(const SuperIntf: ISuperIntf); begin SuperIntf.Blubb; end; |
AW: Tutorial Interfaces
Hallo zusammen, ich habe das Beispiel noch mit einer DB Lösung erweitert. Vielleicht wird es dann besser zu verstehen
|
AW: Tutorial Interfaces
Zitat:
Ich finde interfaces immer dann so richtig überzeugend, wenn es wirklich um Schnittstellen geht (DLL, SOAP, ActiveX, ...)... Aber das sind nur meine zwei Cent. Ich konnte bisher alles - abgesehen von der Referenzzählung - auch mit abstrakten/virtuellen Methoden erreichen kann. |
AW: Tutorial Interfaces
Wobei Du bei "reinen" Klassen aber immer gezwungen bist, eine festgelegte Hierarchie einzuhalten, es sei denn, Du prüfst mit "is-Orgien" jeden geeigneten Typ ab. Und wieso meinst Du, dass man einen Interface-Parameter jemals wieder ändern muss? Genau dafür ist er ja da, dass das eben nicht nötig ist.
|
AW: Tutorial Interfaces
Das ist mir jetzt noch nicht ganz klar, was du meinst. Um mal bei deinem Beispiel zu bleiben - mit einer abstrakten Klasse sieht das ja so aus:
Delphi-Quellcode:
Ich meine nicht, dass man den interface-Parameter jemals wieder ändern muss - ich hatte mich nur auf deine Aussage bezogen, dass man den Parameter halt einmal ändern muss, wenn man das interface neu einführt. Genauso ist es ja hier mit dem Parameter für die abstrakte Klasse: einmal muss man ihn ändern, aber danach nicht mehr.
type
TSuperClass = class procedure Blubb; virtual; abstract; end; TDings = class(TSuperClass) public procedure Blubb; override; end; TBums = class(TSuperClass) public procedure Blubb; override; end; ... procedure TConsumer.Wuppdi(const SuperClass: TSuperClass); begin SuperClass.Blubb; end; Und was meinst du hier mit "Hierarchie einhalten"? Ich muss von der abstrakten Basisklasse ableiten - genauso wie du das interface implementieren musst. Das gibt sich doch eigentlich nichts. |
AW: Tutorial Interfaces
Kannst Du immer und überall sicherstellen, dass die übergebenen Instanzen von einer bestimmten Klasse abgeleitet wurden? In meinem Minimalbeispiel ist das natürlich kein Problem, aber was ist z.B. mit Ableitungen bestehender VCL-Controls? Da bliebe nur die Lösung mit den zig "is"-Abfragen, wenn man auf Interfaces verzichten will. Wenn nicht, lässt man die Ableitung einfach das Interface implementieren, fertig.
|
AW: Tutorial Interfaces
Zitat:
Interfaces sind in der Hinsicht flexibler, weil sie von beliebigen Klassen implementiert werden können und man dann z.B. bei einem Funktionsaufruf nur das entsprechende Interface als Parameter übergibt, dadurch kann man so einer Funktion auch beliebige Objekte übergeben, die keine gemeinsame Basisklasse brauchen. |
AW: Tutorial Interfaces
Exakt, ich habe da mal schnell ein Beispiel gebaut (ich habe die Standard-Benennung einfach beibehalten, da die Komponenten eh keinen tieferen Sinn haben):
Delphi-Quellcode:
unit Unit6;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; type IDisplay = interface ['{B515DBE1-9D0E-4491-BEE8-85805852870B}'] function DisplayString: string; end; TEdit = class(VCL.StdCtrls.TEdit, IDisplay) public function DisplayString: string; end; TLabel = class(VCL.StdCtrls.TLabel, IDisplay) public function DisplayString: string; end; TComboBox = class(VCL.StdCtrls.TComboBox, IDisplay) public function DisplayString: string; end; TWuppdi = class procedure Consume(const Display: IDisplay); end; TForm6 = class(TForm) Edit1: TEdit; ComboBox1: TComboBox; Label1: TLabel; Button1: TButton; Button2: TButton; Button3: TButton; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); private { Private-Deklarationen } FWuppdi: TWuppdi; public { Public-Deklarationen } end; var Form6: TForm6; implementation {$R *.dfm} { TEdit } function TEdit.DisplayString: string; begin Result := Text; end; { TLabel } function TLabel.DisplayString: string; begin Result := Caption; end; { TComboBox } function TComboBox.DisplayString: string; begin if ItemIndex > -1 then Result := Items[ItemIndex] else Result := ''; end; { TWuppdi } procedure TWuppdi.Consume(const Display: IDisplay); begin ShowMessage(Display.DisplayString); end; procedure TForm6.Button1Click(Sender: TObject); begin FWuppdi.Consume(Edit1); end; procedure TForm6.Button2Click(Sender: TObject); begin FWuppdi.Consume(ComboBox1); end; procedure TForm6.Button3Click(Sender: TObject); begin FWuppdi.Consume(Label1); end; procedure TForm6.FormCreate(Sender: TObject); begin FWuppdi := TWuppdi.Create; end; procedure TForm6.FormDestroy(Sender: TObject); begin FWuppdi.Free; end; end. |
AW: Tutorial Interfaces
Hm, du meinst, dass du sowas machen könntest?
Delphi-Quellcode:
Wäre das von der Synatx her richtig und das, was du meinst? Okay, zugegeben, das ginge mit abtrakten Klassen nicht.
TRumsButton = class(TButton,ISuperIntf)
public procedure Blubb; end; [...] var customer: TCustomer; rums: TRumsButton; begin [...] customer.wuppdi(rums); [...] end; PS: Edith hat sich gemeldet, aber ich poste es dennoch mal, um bei den vorherigen, ganz einfachen Beispielen zu bleiben. |
AW: Tutorial Interfaces
Zitat:
Ich implementiere schon mal gern Interfaces in Forms, Frames oder Datenmodulen (z.B. ILogger-Implementierungen, die Log-Meldungen in Memos oder Datenbanken schreiben). Das wäre mit abstrakten Klassen gar nicht möglich. Das Problem mit solchen Tutorials ist halt immer, daß es einfach gehalten sein soll, damit man das dahinter stehende Prinzip versteht. In der Regel gibt es bei solch einfachen Fällen dann natürlich auch valide alternative Lösungen. Ein Tutorial ist eben kein Beispiel für eine Killer-Anwendung. |
AW: Tutorial Interfaces
Zitat:
|
AW: Tutorial Interfaces
Was soll an einem ILogger-Interface kompliziert sein? Da genügt im einfachsten Fall eine Log-Methode mit einem String-Parameter.
|
AW: Tutorial Interfaces
Zitat:
Insofern hat mich die Diskussion, die sich jetzt hier daraus ergeben hat, tatsächlich weitergebracht. Mal sacken lassen und mal schauen, wann ich demnächst auf ein Problem stoße, wo ich das dann auch mal anwenden kann. Danke euch allen für die Anregungen! |
AW: Tutorial Interfaces
Das geht doch auch viel einfacher ohne ein Interface. Eine einfache Klasse reicht.
Interfaces sind einfach nur komplizierter Spökes den man erst wieder umständlich erlernen muss :P Ich selber komme mit normalen Klassen wunderbar klar und habe noch keine Funktionalität vermisst. |
AW: Tutorial Interfaces
Wo ist denn nun der Unterschied zwischen TDings und IDings? Ist I komplizierter als T?
|
AW: Tutorial Interfaces
Zitat:
Aber davon ab Interface in DLL's sind eine feine Sache. Ausgenomen davon wenn da nicht so viele Getter und Setter wären die im Interface mit übernommen werden müssen. gruss |
AW: Tutorial Interfaces
Eigentlich hatte ich meinen Beitrag vorhin verworfen, aber vielleicht hilft er ja doch noch wem weiter ->
Vielleicht darf ich gleich nochmal auf mein Tutorial verlinken: ![]() Neben der schon erwähnten möglichen Referenzzählung (wenn man es braucht und will) arbeitet man bei Interfaces eher mit Funktionalitäten statt mit konkreten Klassen. Jedes Objekt kann mehrere Interfaces unterstützen, was bei Verwendung von Basisklassen in Delphi nicht geht. Ich kann also alle Objekte bewegen, die IMove unterstützen und alle Objekte Loggen, die ILogging unterstützen. Die konkrete Klasse spielt in dem Moment keine Rolle mehr. Jede im Projekt verwendete Klasse kann kein, eins oder beide Interfaces unterstützen. Wenn man ohne Interfaces auskommt spricht da überhaupt nichts dagegen. Der Einsatz von Interfaces erzeugt auch durchaus einigen Mehraufwand und Umstellung beim Umgang mit Objekten. Bei komplexen Projekten kann sich der aber lohnen, da man u.U. mehr Struktur in das Projekt bekommen und ggf. Klassen später auch leichter austauschen kann. Man ist dann halt nicht von einer bestimmten Basisklasse abhängig. |
AW: Tutorial Interfaces
So isses. Immer, wenn es um maximale Flexibilität geht, sind Interfaces das probate Mittel dazu. Für jedes Fitzchen aber nur noch auf Interfaces zu setzen ist in meinen Augen sinnlos. Wie immer hängt es halt vom Einzelfall ab.
|
AW: Tutorial Interfaces
Zitat:
|
AW: Tutorial Interfaces
Zitat:
Denke nicht das er das böse gemeint hat. gruss |
AW: Tutorial Interfaces
Zitat:
Aber ich finde, dass Interfaces ganz und gar nicht das gleiche sind wie normale Klassen. ich finde normale Klassen wesentlich angenehmer zu schreiben. Wenn man X Objekte von Y Objekten ableiten muss, macht man im Grundaufbau irgendetwas falsch wie ich finde. Da helfen auch keine Interfaces. |
AW: Tutorial Interfaces
Kommt halt darauf an für was man es verwendet.
Wenn ich eine Funktion aus meiner DLL öffentlich machen will dann verwende ich Interface weil der Anwender sich dann nicht mehr um das laden der DLL kümmern muss. Zudem erspart es mir für eine Funktion mehrere Exports zu generieren die ich so mit einer Erledigen kann. gruss |
AW: Tutorial Interfaces
Hallo,
wenn ich bestehende Klassen, die nicht von einer Basisklasse abgeleitet sind, um eine gemeinsame Funktionalität erweitern will, geht das nur über Interfaces. |
AW: Tutorial Interfaces
Das Beispiel in #11 von DeddyH zeigt das eigentlich sehr schön.
Ohne Interfaces müsste man Wuppdi so schreiben:
Delphi-Quellcode:
Man muss also an der Stelle alle Klassen konkret kennen und darauf casten.
{ TWuppdi }
procedure TWuppdi.Consume(const O: TObject); begin if (O is TEdit) then ShowMessage((O as TEdit).DisplayString); if (O is TLabel) then ShowMessage((O as TLabel).DisplayString); if (O is TComboBox) then ShowMessage((O as TComboBox).DisplayString); end; Wenn man irgendwann 2 neue Klassen dort anzeigen möchte, muss man diese in der Prozedur nachträglich mit aufnehmen - und in allen anderen Prozeduren, die diese neuen Klassen kennen müssen. Auf eine gemeinsame Basisklasse zurückzugreifen geht hier ja nicht. Mit Interfaces ist es halt einfacher, zu prüfen, ob das vorliegende Objekt von der Prozedur bearbeitet werden kann. Man schaut sich nur noch an, ob das, was ich da habe displayed werden kann oder nicht. Man muss dann nicht mehr wissen, welche Klasse man konkret vorliegen hat und es kann sogar sein, dass man die konkrete Klasse überhaupt nicht kennt. Wie gesagt, man MUSS das natürlich nicht verwenden, aber es ist gut, wenn man es kennt und darauf zurück greifen kann, wenn man mit einfachen Klassen mal nicht so gut zum Ziel kommt. |
AW: Tutorial Interfaces
Der grösste Vorteil von Interfaces ist das die Consumer Klasse gar nichts von der Implementation mitbekommt.
Keinerlei Abhängigkeiten zu anderen Klassen. Jeder der versucht Unit Tests zu schreiben und das auch konsequent :oops: durchzieht will die Vorteile nicht mehr missen. Die einzige Abhängigkeit ist die Interface Unit, fertig. Ich arbeite in der CAD-Branche, wir müssen import und export zu verschiedenen Formaten bereithalten. Unser Klassen haben einfach Methoden die ein Interface entgegennehmen. Welches Format da dann wirklich dahintersteht is egal. Die verschiedenen Formate werden einfach bei einer Factory registriert.
Delphi-Quellcode:
Ob da jetzt ein Step, SAT, Igel oder was auch immer ankommt ist egal.
function readImport(Import : IImport3d) : boolean;
Die einzelnen Bereiche können unabhängig voneinander getestet werden und gut ist.. |
AW: Tutorial Interfaces
Ich verweise da mal schamlos auf meine Reihe von Blog-Artikeln von 2010 zum Visitor Pattern:
![]() ![]() ![]() ![]() Insbesondere Part 2 und 3 gehen auf die Vorteile bei der Verwendung von Interfaces ein. Ist aber auch schon etwas mehr zu lesen... |
AW: Tutorial Interfaces
Was ich mich schon länger frage: Gibt es eigentlich einen bestimmten Grund, warum Interfaces in Delphi keine privaten Methoden haben dürfen? Unter C++ ist das beispielsweise problemlos möglich.
|
AW: Tutorial Interfaces
Hm?
wieso privat? Die Methoden müssen doch implementiert werden, wenn sie privat wären, macht das doch keinen Sinn, oder? |
AW: Tutorial Interfaces
Zitat:
Ich mache das immer so, dann lassen Sich die Funktionen nur über das Interface ansprechen, verhindert einfach dass man aus versehen Klassen-Instanzen und Interfaces mixed. Als IInterface geht es als Tclass nicht |
AW: Tutorial Interfaces
Zitat:
Zitat:
|
AW: Tutorial Interfaces
Zitat:
|
AW: Tutorial Interfaces
Zitat:
|
AW: Tutorial Interfaces
Zitat:
|
AW: Tutorial Interfaces
Zitat:
Delphi-Quellcode:
verwenden.
strict private
|
AW: Tutorial Interfaces
Zitat:
|
AW: Tutorial Interfaces
Interfaces haben in C++ normalerweise auch keine privaten Member, sonder sind als public pure abstrakte Methoden implementiert.
Ich denke da gibt es keinen grossen Unterschied zu Delphi:
Code:
struct IWriter { // structs immer public
virtual void Write() = 0; }; class FileWriter : public IWriter { public: void Write() override { doTheWriting(); } }; |
AW: Tutorial Interfaces
Warum funktioniert das Beispiel von DeddyH nur, wenn alles in der selben Unit implementiert ist? Wenn ich diesen kompletten Interface Teil in einer Unit2 auslagere so bekomme ich die Compiler Fehlermeldung "E2010 Inkompatible Typen IDisplay und TEdit".
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:10 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 by Thomas Breitkreuz