Methodenzeiger casten



  • Folgender Code ist nicht schön, das weiß ich selber 😉
    Aber der bisher verwendete Code ist noch viel unschöner.

    Funktioniert der Code so oder ist das abhängig vom Compiler?
    Im BCC32 vom Embarcadero C++Builder XE2 tut der Code was er soll.

    In der Anwendung die den Code verwenden soll ist sichergestellt, dass die Methodenzeiger nur mit Instanzen der passenden Klassen gerufen werden.

    #include <tchar.h>
    #include <iostream>
    
    class A
    {
    public:
       virtual void M1(int i)
       {
          std::cout << "A:M1 " << i << "\n"; 
       }
    };
    
    class B :public A
    {
    public:
       virtual void M1(int i)
       {
          std::cout << "B:M1 " << i << "\n";  
       }
       virtual void M2(int i)
       {
          std::cout << "B:M2 " << i << "\n"; 
       }
    };
    
    typedef void (A::*AddFN)(int);
    
    int _tmain(int argc, _TCHAR* argv[])
    {
       A a;
       B b;
       AddFN FN = &A::M1;
       A* obj = &a;
       (obj->*FN)(5);
       obj=&b;
       (obj->*FN)(5);
       FN = reinterpret_cast<void (A::*)(int)>(&B::M2);
       (obj->*FN)(6);
    
       // das knallt natürlich
       //obj = &a;
       //(obj->*FN)(6);
    
       char ch;
       std::cin >> ch;
    	return 0;
    }
    

  • Mod

    MichelRT schrieb:

    Funktioniert der Code so oder ist das abhängig vom Compiler?

    Letzteres, weil der falsche Cast verwendet wird. Hier ist static_cast angebracht. Für die Umgekehrung impliziter Konvertierungun ist - soweit ein Cast überhaupt erforderlich ist - grundsätzlich static_cast zuständig, abgesehen von ein paar Ausnahmen, die dynamic_cast oder const_cast verlangen.



  • Ok, mit einem static_cast wäre es definiertes Verhalten?


  • Mod

    MichelRT schrieb:

    Ok, mit einem static_cast wäre es definiertes Verhalten?

    ja. Für die Konvertierung selbst ist (i.W.) nur erforderlich, dass A Basisklasse von B ist.
    Für die Legalität des Aufrufes über den Meberfunktionszeiger ist erforderlich, dass das Objekt (d.h. entscheidend ist hier der dynamische Typ), mit dem dieser Zeiger verwendet wird, diese Memberfunktion auch tatsächlich enthält. Beides ist gegeben.



  • camper schrieb:

    Für die Legalität des Aufrufes über den Meberfunktionszeiger ist erforderlich, dass das Objekt (d.h. entscheidend ist hier der dynamische Typ), mit dem dieser Zeiger verwendet wird, diese Memberfunktion auch tatsächlich enthält. Beides ist gegeben.

    Gut, genau das war auch meine Überlegung.
    Schön ist zwar anders ... aber wenn das restliche Progtramm sicherstellt, dass die Methoden nur mit passenden Instanzen gerufen werden, vertretbar.


  • Mod

    Ich könnte mir vorstellen, dass bestimmte mit dem Standard inkompatible Compilererweiterungen Probleme machen können (wie die - zum Glück abschaltbaren - unterschiedlich großen Memberfunktionszeiger bei Visual C++).

    struct A {};
    struct B : A { virtual void f(); };
    
    typedef void (A::*memfun)();
    memfun mp = static_cast<memfun>(&B::f);
    B b;
    A* p = &b;
    (p->*mp)();
    

    könnte bei so einem ggf. Compiler schiefgehen, da A nicht polymorp ist, unterstützt der zugehörige Memberfunktionszeiger dann evtl. keine virtuellen Memberfunktionen.

    Praktisch dürfte dieses Problem in dieser Form allerdings nicht auftreten, da As in realem Code hoffentlich polymorph sind.



  • Danke!


Anmelden zum Antworten