Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Cast class to interface
delphijanka - Fr 17.09.10 16:13
Titel: Cast class to interface
Hallo. Habe ein Problem. Gegeben:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:
| type ILaufer = Interface procedure laufe; end;
type ISpringer = Interface procedure springe; end;
type TTier = class(TInterfacedObject) procedure esse; end;
type TElefant = class(TTier , ILaufer) procedure laufe; end;
type TKenguru = class(TTier, TSpringer) procedure springe; end;
type TLeopard = class(TTier, TLaufer, TSpringer) procedure laufe; procedure springe; end; |
So verwalte ich meine Tiere:
Delphi-Quelltext
1: 2:
| var Tiere = array of TTier; |
Nun möchte ich die Fähigkeiten der Tiere ausnutzen, was in Pseudo so aussieht:
wenn Tier[i] ist ein ISpringer
dann (Tier[i] als ISpringer).springe;
Ich weiß allerdings nicht, wie es geht. Kann mir einer helfen? Danke.
Moderiert von
Narses: Code- durch Delphi-Tags ersetzt
Martok - Fr 17.09.10 16:40
delphijanka hat folgendes geschrieben : |
Nun möchte ich die Fähigkeiten der Tiere ausnutzen, was in Pseudo so aussieht:
wenn Tier[i] ist ein ISpringer
dann (Tier[i] als ISpringer).springe;
Ich weiß allerdings nicht, wie es geht. |
Doch, tust du. Steht alles schon da, wenn du das 1:1 nach Englisch (oder Pascal :D ) übersetzt:
Delphi-Quelltext
1: 2:
| if Tier[i] is ISpringer then (Tier[i] as ISpringer).springe; |
Oder, schöner (und ggf. einfacher, wenn du mehrere Methoden aufrufen willst):
Delphi-Quelltext
1: 2: 3: 4:
| var Springtier: ISpringer;
if Tier[i].QueryInterface(ISpringer, Springtier)=S_OK then SpringTier.springe; |
delphijanka - Fr 17.09.10 16:51
@Martok
Lösung (a):
- geht schon mal nicht: "Operator not applicable to this operand type"
Lösung (b):
- die Methode QueryInterface ist nicht bekannt.
- Was schreibe ich an der {...} - Stelle? Wie erzeuge ich ein Objekt von ISpringer?
Martok - Fr 17.09.10 17:12
(a) Könnte sogar stimmen, damit man sowas tun kann, braucht das Interface eine GUID. Steht irgendwo in der Delphi-Hilfe welche Tastenkombination das war und was genau man damit tun soll.
(b) Faszinierend. Das ist in TInterfacedObject wirklich protected. Dann eben anders und noch schöner :P
Delphi-Quelltext
1: 2: 3: 4:
| var Springtier: ISpringer;
if Supports(Tier[i], ISpringer, Springtier) then SpringTier.springe; |
Anstelle der Auslassung dürfte wohl mindestens ein
begin und ein
for kommen. Aber das musst du schon wissen...
delphijanka - Fr 17.09.10 17:15
@Martok
Wie ich erstelle ich ein Objekt vom Interface-Typ. In diesem Fall vom ISpringer?
mkinzler - Fr 17.09.10 19:05
Man kann kleine Instanzen von Interfacen erzeugen. Du musst eine Klasse von dem Interface ableiten und diese dann instantiieren
delphijanka - Mo 20.09.10 00:55
@Martok und mkinzler:
Die Prozeduren QueryInterface oder Supports erwarten Interface-Parameter vom Typ TGuid, wogegen ISpringer nicht von diesem Typ ist.
Daher kommt die Fehlermeldung. Gibt es denn keine Lösung für mein Problem in Delphi? Muss ich unbedingt die Deklaration mit TGuid machen?
(Warum ist das in Delphi nur so kompliziert?... :( ). Wäre sehr dankbar für eine funktionierende Lösung.
Martok - Mo 20.09.10 01:11
Martok hat folgendes geschrieben : |
| (a) Könnte sogar stimmen, damit man sowas tun kann, braucht das Interface eine GUID. Steht irgendwo in der Delphi-Hilfe welche Tastenkombination das war und was genau man damit tun soll. |
Hilfeseiten dazu: "Schnittstellentypen" (kriegt man bei F1 auf "interface") und "Identifikation einer Schnittstelle" von da aus.
Sobald du das Interface identifizierbar gemacht hast durch Vergabe eine GUID kannst du es anstelle von GUIDs verwenden.
delfiphan - Mo 20.09.10 12:22
Wenn du innerhalb der Hierarchie bleibst und nicht irgendwie quer oder hoch castest, dann kannst du einfach ILaufer(...) schreiben und brauchst auch keine GUIDs.
Also von TTier auf ISpringer brauchst du GUIDs, von TLeopard nicht. Hängt ein wenig vom Anwendungsfall ab.
delphijanka - Fr 24.09.10 15:08
zu der Lösung, wie Martok sie vorgeschlagen hat, eine kleine Abwandlung, die
ich in meinem Prog benutze:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| var SpringTier: IPDFErzeuger; Unk: IUnknown; begin if Tier[i].GetInterface(IUnknown, Unk) and Supports(Unk, ISpringer, SpringTier) then SpringTier.springe; |
Und dabei habe ich ein Problem: das Objekt Tier[i] wird nach diesem Code automatisch freigegeben. Liegt es an Referenzzählung? Wie kann ich erreichen, dass es nicht freigegeben wird (ich muss Tier[i] ja weiter benutzen...)
bummi - Fr 24.09.10 15:42
Hat mich auch schon viele Nerven gekostet...
nimm TinterFacedPersistent, dann tickt es so wie wir es wollen.
delphijanka - So 26.09.10 17:51
@bummi
Bei der Nutzung von TInterfacedPersistent kommt der Fehler, der Bezeichner sei undefiniert.
(benutze zur Zeit Delphi 5)
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!