Zugriff auf __interface-Methoden



  • Und da schimpft man immer auf den Vorführeffekt. Gerade habe ich nochmal ein Beispiel erstellt, weil mein ursprüngliches im Büro ist - und jetzt tut's!

    Trotzdem Danke,
    Marc



  • Mist! Jetzt ist ein weiteres Problem aufgetaucht. Beim Zugriff auf die Methoden des gecasteten Objekts gibt es eine Zugriffsverletzung.

    Hier ist der Code. Er soll dazu dienen, eine eigene Focus-Steuerung zu implementieren:

    // Schnittstelle für Komponenten um Festzulegen, ob sie den Focus erhalten können.
    
    __interface IFocusInfo
    {
      public:
        virtual bool __fastcall GetFocusErlaubt() = 0;
        virtual void __fastcall SetFocusErlaubt(bool Wert) = 0;
        __property bool FocusErlaubt = {read = GetFocusErlaubt,
                                        write = SetFocusErlaubt};
    };
    
    // Ein TEdit, das die Schnittstelle Implementiert
    
    class PACKAGE TEditWf : public TEdit, public IFocusInfo
    {
    private:
      bool FFocusErlaubt;
    public:
      __fastcall TEditWf(TComponent* Owner);
      virtual bool __fastcall GetFocusErlaubt();
      virtual void __fastcall SetFocusErlaubt(bool Wert);  
    __published:
      __property bool FocusErlaubt = {read = GetFocusErlaubt,
                                      write = SetFocusErlaubt};
    };
    
    // Im Form werden meherere Edits plaziert. Zu Testzwecken wird in ihre OnKeyDown
    // Methode dieser Code geschrieben, der bei jedem Tastendruck den Focus weiter
    // geben soll und dabei nur die Komponenten mit FocusErlaubt=true
    // berücksichtigt.
    
    void __fastcall TForm1::EditWf1KeyDown(TObject *Sender, WORD &Key,
          TShiftState Shift)
    {
      TList* TabOrderListe = new TList();
      GetTabOrderList(TabOrderListe);
      int IndexActiveControl = TabOrderListe->IndexOf(ActiveControl);
      IFocusInfo* FocusInfo = (IFocusInfo*)TabOrderListe->Items[IndexActiveControl];
      int I = IndexActiveControl;
      while(!FocusInfo->GetFocusErlaubt()) [b]// Hier tritt die Zugriffsverletzung auf.[/b]
      {
        if(I < TabOrderListe->Count - 1)
        {
          I++;
        }
        else
        {
          I = 0;
        }
        FocusInfo = (IFocusInfo*)TabOrderListe->Items[I];
      }
      ActiveControl = (TWinControl*)FocusInfo;
    }
    

    Im Form befinden sich nur Komponenten, die die Schnittstelle auch wirklich implementieren.

    Gruß
    Marc



  • Update: Wenn man

    IFocusInfo* FocusInfo = (IFocusInfo*)TabOrderListe->Items[IndexActiveControl];
    

    durch

    IFocusInfo* FocusInfo =
    dynamic_cast<IFocusInfo*>(TabOrderListe->Items[IndexActiveControl]);
    

    ersetzt gibt es übrigens schon beim Compilieren einen Fehler:
    "E2307 Typ 'void' ist keine definierte Klasse bei virtuellen Funktionen"

    Noch irgendwelche Ideen?

    Gruß
    Marc



  • Mach mal das: (Txxxx ist der Typ, den diese Item-Property halt hat, ich weiß es ja nicht...)

    Txxxx *item = TabOrderListe->Items[IndexActiveControl];
    IFocusInfo* FocusInfo = dynamic_cast<IFocusInfo*>(item);
    


  • item ist statisch vom Typ void*. Zur Laufzeit finden sich darin Subklassen von TControl. Ich habe jetzt folgendes versucht:

    void* item = TabOrderListe->Items[IndexActiveControl];
      IFocusInfo* FocusInfo = dynamic_cast<IFocusInfo*>(item);
    

    Ergibnis: Selber Compiler-Fehler ("E2307 Typ 'void' ist keine definierte Klasse bei virtuellen Funktionen")



  • Achso, ja das kann nicht gehen. Ich weiß zwar jetzt nicht, ob der Standard das verlangt, aber zumindest Borland verlangt, dass ein Typ virtuelle Funktionen hat, damit man ihn dynamic_casten kann.



  • Das kann aber auch nicht die Wurzel des Problems sein. Ich hab' jetzt 'mal folgendes probiert (Änderungen fett):

    void __fastcall TForm1::EditWf1KeyDown(TObject *Sender,
          WORD &Key, TShiftState Shift)
    {
      TList* TabOrderListe = new TList();
      GetTabOrderList(TabOrderListe);
      int IndexActiveControl = TabOrderListe->IndexOf(ActiveControl);
      [b]IFocusInfo* FocusInfo = dynamic_cast<IFocusInfo*>(Controls[IndexActiveControl]);[/b]
    
      int I = IndexActiveControl;
      while(!FocusInfo->GetFocusErlaubt()) // Hier tritt die Zugriffsverletzung auf.
      {
        if(I < TabOrderListe->Count - 1)
        {
          I++;
        }
        else
        {
          I = 0;
        }
        FocusInfo = (IFocusInfo*)TabOrderListe->Items[I];
      }
      ActiveControl = (TWinControl*)FocusInfo;
    }
    

    Das wäre zwar ein semantischer Fehler müsste beim Kompilien aber durchlaufen, wenn es daran liegen würde, denn die Elemente von "Controls" sind vom Typ TControl* und das hat ja virtuelle Funktionen.

    Es kommt aber der Fehler "E2031 Typumwandlung von 'TControl *' nach 'IFocusInfo *' nicht zulässig"

    Gruß
    Marc



  • Hat wirklich keiner eine Idee dazu? Es kann doch nicht sein, dass noch nie jemand versucht hat, über eine Schnittstelle auf ein Objekt zuzugreifen.
    Auch mit der Information, dass es definitiv nicht geht wäre mir notfalls geholfen, dann müsste ich mir keine Gedanken mehr darüber machen, was ich falsch mache.

    Gruß
    Marc



  • Hallo,

    1. TList::Items ist vom Typ void*. Das kannst du natürlich nicht mit einem dynamic_cast in deinen gewünschten Typ umwandeln. Entweder den (schon von dir verwendeten C-Cast) oder einen reinterpret_cast.

    2. Du sagst, dass dein TList Objekte vom Typ TControl enthält. Das kannst du ja schwerlich nach IFocusInfo casten da die beiden Klassen ja nicht in einer Vererbungshierarchie stehen. Vielleicht geht ja ein cast nach TEditWf.

    3. Mehrfachvererbung mit VCL-Klassen stellt normalerweise ein Problem dar, da VCL-Klassen in Pascal geschrieben sind und Pascal nunmal keine Mehrfachverebung unterstützt. Allerdings ist bei dir nur eine VCL-Klasse (TEdit) beteiligt. Da weiß ich nicht genau ob das gerade noch geht.

    4. Dir ist klar das das Schlüsselwort __interface in C++ eigentlich nicht existiert? Hier (im BCB) ist es lediglich ein define auf class

    Ciao



  • Hallo

    3. Mehrfachvererbung mit VCL-Klassen stellt normalerweise ein Problem dar, da VCL-Klassen in Pascal geschrieben sind und Pascal nunmal keine Mehrfachverebung unterstützt. Allerdings ist bei dir nur eine VCL-Klasse (TEdit) beteiligt. Da weiß ich nicht genau ob das gerde noch geht.

    Nein, Mehrfachvererbung ist in keinem Fall mit VCL-Klassen möglich :

    E2278 VCL-Klassen dürfen nicht mehrere Basisklassen haben

    bis bald
    akari



  • Das ist schon richtig, aber ist die neue Klasse denn überhaupt eine VCL-Klasse? Wir sind jetzt ja immerhin in C++.
    Mich hat es nur gewundert, dass er hier eine Zugriffsverletzung bekommt. Wenn die Mehrfachvererbung nicht ginge hätte doch eigentlich schon der Compiler meckern müssen.



  • Hallo

    die Fehlermeldung habe ich bei diesem Test bekommen :

    class N
    {
      public :
      N() {};
      };
    
    class Test : public TEdit, public N
    {
      public :
      Test() : TEdit(NULL), N() {};
      };
    

    bis bald
    akari



  • akari schrieb:

    Mehrfachvererbung ist in keinem Fall mit VCL-Klassen möglich

    Jein. Mehrfache Schnittstellenvererbung geht auch mit VCL-Klassen (so ähnlich wie in Java).
    Also z.B. sowas:

    class MeinInterface
    {
    public:
       virtual void meineReinVirtuelleMethode() = 0;
       __property int EineEigenschaft = {read=getEineEigenschaft, write=setEineEigenschaft};
    protected:
       virtual int getEineEigenschaft() = 0;
       virtual void setEineEigenschaft(int Value) = 0;
    };
    
    class MeineVCLKlasse: public TComponent, public MeinInterface
    {
    public:
       // Konstruktor, Destruktor...
       virtual void meineReinVirtuelleMethode();
    protected:
       virtual int getEineEigenschaft();
       virtual void setEineEigenschaft(int Value);
    };
    

    Das Beispiel sollte sich kompilieren lassen (obwohl ich's nicht ausprobiert habe).

    Wenn man Komponenten im Designer visuell miteinander verbinden will (über den Objektinspektor),
    müssen die Komponenten natürlich auch von TComponent erben.

    Gruß,

    Alexander



  • Hallo

    Das Beispiel sollte sich kompilieren lassen (obwohl ich's nicht ausprobiert habe).

    Also ich habe dein Beispiel kopiert und es kommt ebenfalls die von mir bereits gepostete Fehlermeldung.
    Muß da noch irgendwas eingestellt/geändert werden?

    bis bald
    akari



  • akari schrieb:

    Also ich habe dein Beispiel kopiert und es kommt ebenfalls die von mir bereits gepostete Fehlermeldung.
    Muß da noch irgendwas eingestellt/geändert werden?

    Ich verwende Schnittstellenvererbung mit VCL-Klassen an einigen Stellen, allerdings mit TForm und TObject,
    mit TComponent habe ich das noch nie probiert. Allerdings wüsste ich nicht, was dagegen sprechen sollte.
    Welche BCB-Version verwendest Du denn?

    Gruß,

    Alexander

    Edit: Habe mal meinen Code in die Header-Datei des automatisch erstellten Formulars eines neuen Projekts kopiert
    und bei mir wird das einwandfrei kompiliert.



  • Kann es sein, dass es an der BCB-Variante liegt. In diesem Thread http://www.c-plusplus.net/forum/viewtopic.php?t=48437&highlight=mehrfachvererbung wird gesagt, dass der BCB6 damit zurechtkommt.



  • Hallo

    ich benutzte BCB 5.01. Dann liegt es wohl daran.
    Denn das letzte Beispiel aus Braunsteins Link führt ebenfalls zu der Fehlermeldung. Wenn das bei euch mit V6 auch funktioniert, ist es klar.

    bis bald
    akari



  • Braunstein schrieb:

    Hallo,
    2. Du sagst, dass dein TList Objekte vom Typ TControl enthält. Das kannst du ja schwerlich nach IFocusInfo casten da die beiden Klassen ja nicht in einer Vererbungshierarchie stehen. Vielleicht geht ja ein cast nach TEditWf.

    Nach TEditWf kann ich schon casten, nur bringt es mir nichts. Es soll ja später mehrere Komponenten geben, die IFocusInfo implementieren. Da ich beim Duchlauf durch die Liste nicht weiß, ob da an einem bestimmt Index ein TEditWf oder eine andere Komponente, die die Schnittstelle ebenfalls implementiert, steht, will ich nach IFocusInfo casten. (Wie man es in Java machen würde, richtig erkannt Alexander.)

    Wenn ich mir die obigen Beiträge - für die ich mich herzlich bedanke - so ansehe, bleibt wohl festzuhalten, dass die Mehrfachvererbung von Schnittstellen beim BCB für die Programmierung vollkommen nutzlos ist und nur insofern einen Vorteil bringt, dass in einem Mehr-Entwicklerprojekt die Koordination verbessert wird, wenn Schnittstellen formal definiert sind und vom Compiler überprüft werden können, oder?

    Gruß
    Marc


Anmelden zum Antworten