AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign Zuweisung eines Methodenzeigers bei vererbten Interfaces
Thema durchsuchen
Ansicht
Themen-Optionen

Zuweisung eines Methodenzeigers bei vererbten Interfaces

Ein Thema von dpg123 · begonnen am 21. Apr 2017 · letzter Beitrag vom 21. Apr 2017
Antwort Antwort
Seite 1 von 2  1 2      
dpg123

Registriert seit: 13. Apr 2015
22 Beiträge
 
Turbo Delphi für Win32
 
#1

Zuweisung eines Methodenzeigers bei vererbten Interfaces

  Alt 21. Apr 2017, 13:03
Hallo liebes Forum,

entschuldigt den etwas kryptischen Titel. Konnte die Frage iwie nicht prägnanter in einem Satz zusammenfassen...

Ich habe folgendes Design, welches ich gerne benutzen würde:

Delphi-Quellcode:
  IInterfA = interface(IInterface)
  ['{47B0ED79-41C2-4F2F-BA29-521D6B9872FB}']

    function exec1(): string;

  end;

  IInterfB = interface(IInterfA)
  ['{47B0ED79-41C2-4F2F-BA29-521D6B9872FB}']

    function exec2(): string;

  end;


  TImplB = class(TInterfacedObject,IInterfB)

    function exec1(): string;

    function exec2(): string;

  end;


  MInterfA = function(): IInterfA of object;

  MInterfB = function(): IInterfB of object;


  TForm1 = class(TForm)

    procedure FormCreate(Sender: TObject);

  public

    getInterfA: MInterfA;

  published

    function factoryB(): IInterfB;

  end;
Aufgabe, Frage, Diskussion ist jetzt die Zuweisung der Function factoryB() zur Methodenzeiger-Variable getInterfA.

Eine Möglichkeit für die Zuweisung habe ich gefunden:

Delphi-Quellcode:

procedure TForm1.FormCreate(Sender: TObject);
var
  lB: MInterfB;

begin

  lB := self.factoryB;

  Self.getInterfA := MInterfA( lB );

  ShowMessage(self.getInterfA.exec1());

end;

function TForm1.factoryB: IInterfB;
begin
  result := TImplB.create();
end;

{ TImplB }

function TImplB.exec1: string;
begin
  Result := 'Hello 1';
end;

function TImplB.exec2: string;
begin
  Result := 'Hello 2';
end;
Geht die Zuweisung auch direkt, ohne die Variable lB und damit auch ohne Anlegen des Typs MInterfB?

Das showmessage hat gemacht was es soll, aber tappe ich mit dem Design in iwelche Fallen? Gibt es Situation, in denen dieser Downcast Probleme macht? Ist es überhaupt gutes Design? Wie könnte man es eleganter lösen?

Dank und Gruß
  Mit Zitat antworten Zitat
Benutzerbild von Olli73
Olli73

Registriert seit: 25. Apr 2008
Ort: Neunkirchen
741 Beiträge
 
#2

AW: Zuweisung eines Methodenzeigers bei vererbten Interfaces

  Alt 21. Apr 2017, 13:39
Warum nicht einfach

Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
var
  lB: MInterfB;
begin
  ShowMessage(factoryB.exec1);
  (*
  lB := self.factoryB;
  Self.getInterfA := MInterfA( lB );
  ShowMessage(self.getInterfA.exec1());
  *)
;
end;
Oder habe ich dein Problem falsch verstanden?
  Mit Zitat antworten Zitat
dpg123

Registriert seit: 13. Apr 2015
22 Beiträge
 
Turbo Delphi für Win32
 
#3

AW: Zuweisung eines Methodenzeigers bei vererbten Interfaces

  Alt 21. Apr 2017, 13:46
Warum nicht einfach

Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
var
  lB: MInterfB;
begin
  ShowMessage(factoryB.exec1);
  (*
  lB := self.factoryB;
  Self.getInterfA := MInterfA( lB );
  ShowMessage(self.getInterfA.exec1());
  *)
;
end;
Oder habe ich dein Problem falsch verstanden?
Das Ziel ist factoryB über den Datentyp MInterfA mit der Variable getInterfA an andere Programmteile zu übergeben. Der vorgestellte Code war nur ein Minimalbsp um das Problem zu veranschaulichen.
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

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

AW: Zuweisung eines Methodenzeigers bei vererbten Interfaces

  Alt 21. Apr 2017, 13:48
Verstehe ich richtig, dass Du prüfen willst, ob Dein Objekt nicht nur IInterfB sondern auch IInterfA unterstützt?

Dann ginge das vielleicht so:

Delphi-Quellcode:
TImplB = class(TInterfacedObject, IInterfB, IInterfA)

...
var
  lA: IInterfA;

if Supports(lB, IInterfB, lA) then
  DoSomething(lA);
Das geht mit jedem Interface, unabhängig davon, ob es sich um Ableitungen handelt oder nicht.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
dpg123

Registriert seit: 13. Apr 2015
22 Beiträge
 
Turbo Delphi für Win32
 
#5

AW: Zuweisung eines Methodenzeigers bei vererbten Interfaces

  Alt 21. Apr 2017, 14:00
Verstehe ich richtig, dass Du prüfen willst, ob Dein Objekt nicht nur IInterfB sondern auch IInterfA unterstützt?

Dann ginge das vielleicht so:

Delphi-Quellcode:
TImplB = class(TInterfacedObject, IInterfB, IInterfA)

...
var
  lA: IInterfA;

if Supports(lB, IInterfB, lA) then
  DoSomething(lA);
Das geht mit jedem Interface, unabhängig davon, ob es sich um Ableitungen handelt oder nicht.
Die Signatur von MInterfA = function(): IInterfA of object; unterscheidet sich von function factoryB(): IInterfB; ja nur durch einen "Downcast". Meiner Meinung eine gültige Zuweisung, bzw. ein legitimes Design.

Der Compiler lässt mich keine direkte Zuweisung machen: Self.getInterfA := self.factoryB; Dafür könnte es ja Gründe geben, die ich nicht verstehe/kenne, aber gerne wissen würde. Daher meine Fragen nach der einfachsten Art der Zuweisung und ob es Argumente gibt, dies nicht zu tun, bzw was dabei zu beachten ist.

Geändert von dpg123 (21. Apr 2017 um 14:10 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

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

AW: Zuweisung eines Methodenzeigers bei vererbten Interfaces

  Alt 21. Apr 2017, 14:12
Der Compiler lässt mich keine direkte Zuweisung machen: Self.getInterfA := self.factoryB;
Versuche mal nur diese Änderung:
TImplB = class(TInterfacedObject, IInterfB, IInterfA)
IInterfA wird nicht automatisch unterstützt, nur weil IInterfB davon abgeleitet ist. Du musst dieses also explizit zusätzlich angeben.
Dann solltest Du auf Deine Methoden (die ich nicht wirklich verstehe, zumal die Implementierungen im Beispiel fehlen) verzichten können.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Benutzerbild von Olli73
Olli73

Registriert seit: 25. Apr 2008
Ort: Neunkirchen
741 Beiträge
 
#7

AW: Zuweisung eines Methodenzeigers bei vererbten Interfaces

  Alt 21. Apr 2017, 14:14
Nur zum Verständnis: Aus dem Feld "getInterfA: MInterfA;" was sich wie eine Methode anhört (wegen dem get), eine echte Methode zu machen, ist in deinem Fall keine Lösung?
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.159 Beiträge
 
Delphi 10 Seattle Enterprise
 
#8

AW: Zuweisung eines Methodenzeigers bei vererbten Interfaces

  Alt 21. Apr 2017, 14:21
Im Endeffekt geht es dir doch um Kovarianz für Rückgabewerte, oder? Interfaces an sich haben damit eigentlich gar nichts zu tun. Du willst dass ein Methodenzeiger auf eine "Formenfabrik"-Methode auf eine "Kreisfabrik"-Methode oder eine "Trapezfabrik"-Methode beinhalten kann.

Vereinfachtes Beispiel:
Delphi-Quellcode:
program Project19;

uses System.SysUtils;

type
   TBase = class(TObject);
   TSub = class(TBase);

function createBase(): TBase;
begin
   Result := TBase.Create();
end;

function createSub(): TSub;
begin
   Result := TSub.Create();
end;

var
   baseFactory: TFunc<TBase>;
   subFactory: TFunc<TSub>;
begin
   baseFactory := createBase;
   //baseFactory := createSub; // E2010, kann Delphi nicht

   subFactory := createSub;
   //subFactory := createBase; // E2010, war zu erwarten
end.

Das geht in Delphi nicht, Delphi kann keine Kovarianz für Rückgabetypen. Ebenfalls leider nicht für z.B. Var-parameter.

Der erste QC-Eintrag sogar schon aus 2005

http://qc.embarcadero.com/wc/qcmain.aspx?d=16089



Sprachen wie Java z.B. können es:
https://blogs.oracle.com/sundararaja..._types_in_java
  Mit Zitat antworten Zitat
dpg123

Registriert seit: 13. Apr 2015
22 Beiträge
 
Turbo Delphi für Win32
 
#9

AW: Zuweisung eines Methodenzeigers bei vererbten Interfaces

  Alt 21. Apr 2017, 14:58
Nur zum Verständnis: Aus dem Feld "getInterfA: MInterfA;" was sich wie eine Methode anhört (wegen dem get), eine echte Methode zu machen, ist in deinem Fall keine Lösung?
Ja, der Name verwirrt wirklich, sorry.

Hm, könnte evt ein Workaround sein... In der Praxis ist die Variable getInterfA: MInterfA; nicht im selben Objekt wie die function factoryB(): IInterfB; dh ich brauche schon mal ieinen Datentyp um factoryB() an andere Teile zu übergeben, aber man könnte natürlich eine Methode in Form1 deklarieren, die den Cast macht:

Delphi-Quellcode:
TForm1 = class(TForm)

    procedure FormCreate(Sender: TObject);

  public

    getInterfA: MInterfA;

  published

    function factoryACast(): IInterfA;

    function factoryB(): IInterfB;

  end;

implementation

procedure TForm1.FormCreate(Sender: TObject);
begin

  Self.getInterfA := Self.factoryACast;

  ShowMessage(self.getInterfA.exec1());

end;

function TForm1.factoryACast: IInterfA;
begin
  Result := self.factoryB();
end;

function TForm1.factoryB: IInterfB;
begin
  result := TImplB.create();
end;
damit könnte ich mir den Typ MInterfB schon mal sparen... Könnte schöner/sauberer als meine Lösung oben sein !?

Trotzdem würden mich obigen Fragen weiterhin interessieren ...

Zitat:
Im Endeffekt geht es dir doch um Kovarianz für Rückgabewerte, oder? Interfaces an sich haben damit eigentlich gar nichts zu tun. Du willst dass ein Methodenzeiger auf eine "Formenfabrik"-Methode auf eine "Kreisfabrik"-Methode oder eine "Trapezfabrik"-Methode beinhalten kann.
Denke ja... muss dazu sagen, dass ich nur Delphi 2006 und keine Generics zur Verfügung habe... daher hab ich versucht zu tricksen (s.o.)... mit welchen Konsequenzen ist mir weiterhin unklar...
  Mit Zitat antworten Zitat
Benutzerbild von Olli73
Olli73

Registriert seit: 25. Apr 2008
Ort: Neunkirchen
741 Beiträge
 
#10

AW: Zuweisung eines Methodenzeigers bei vererbten Interfaces

  Alt 21. Apr 2017, 15:11
Denke ja... muss dazu sagen, dass ich nur Delphi 2006 und keine Generics zur Verfügung habe... daher hab ich versucht zu tricksen (s.o.)... mit welchen Konsequenzen ist mir weiterhin unklar...
Wenn ich Günther richtig verstanden habe, liegt es nur an Delphi: Es merkt nicht, dass dein "Downcast" beim Rückgabetyp eigentlich ohne Probleme zulässig wäre und bringt stattdessen eine Fehlermeldung.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 21:05 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