Methode zurückgeben



  • Hallo Leute,

    ich bin erst seit Kurzem von Delphi zu C++ konvertiert und habe jetzt mal angefangen mir einen eigenen Wrapper der WinAPI zu bauen (klingt jetzt nach API-Frage, ist es aber keine).

    Dazu habe ich mal dieses Tutorial gemacht http://www.gamedev.net/reference/articles/article1810.asp - im Prinzip gehts darin um eine Fensterklasse mit dynamischer Messagemap (also kein switch). Gelöst wird das ganze per std::map.

    Funktionierte dann (nach einigen kleinen Anpassungen wegen neuerer STL usw.) auch alles wunderbar. Jetzt möchte ich allerdings anfangen andere Komponenten zu entwickeln, dazu wäre es schön wenn ich die Messagehandler einfach vererben könnte und ggf. dann abändern. Das Problem bei dem Tutorial ist jedoch, dass die Handler einfache Funktionen und keine Methoden sind. Also habe ich als erstes mal folgendes gemacht:

    //vorher: typedef long (* tyMessageHandler)(CWindow &, HWND, long, long);
    typedef long (CWindow::* tyMessageHandler)(CWindow &, HWND, long, long);
    typedef std::map<long, tyMessageHandler> tyMessageMap;
    typedef tyMessageMap::iterator tyMessageIterator;
    
    //Handler werden dann so zugewiesen (im Konstruktor):
    RegisterMessageHandler(WM_CLOSE, &CWindow::OnClose);
    

    Und jetzt das Problem. Es gibt eine statische Routingfunktion, die das jeweilige Fenster ermittelt und prüft ob ein Handler für die Message registriert wurde.

    Wenn nein -> DefWndProc

    Wenn ja:

    tyMessageIterator it;
    CWindow *wnd = 0;
    
    wnd = reinterpret_cast<CWindow *>(::GetWindowLong(hwnd, GWL_USERDATA));
    it = wnd->GetMessageHandler(message);
    
    if(it != wnd->m_MsgHandlers.end())
    return (it->second)(*wnd, hwnd, wparam, lparam);
    

    VC++ 2010 RC2 schrieb:

    error C2064: Ausdruck ergibt keine Funktion, die 4 Argumente übernimmt

    Ich schätze jetzt mal dass das Problem darin liegt dass der Compiler nicht weis zu welcher Instanz von CWindow der Handler gehört.

    Hab auch ein wenig rumexperimentiert,

    return wnd.* (it->second)(*wnd, hwnd, wparam, lparam);
    

    funktioniert jedenfalls auch nicht.

    Hat irgendwer ne Idee was ich da machen könnte?

    Danke schonmal 👍

    Grüße,

    spline



  • Das Problem ist, dass das hier:

    typedef long (CWindow::* tyMessageHandler)(CWindow &, HWND, long, long);
    

    nicht 4, sondern 5 Parameter sind. Der erste (Zeiger auf ein CWindow Objekt) ist implizit.
    Du hast ja selbst gesagt, dass es keine Memberfunktion ist, also musst du das emulieren und das geht nicht, wenn du trotzdem eine Memberfunktion nehmen willst. Nimm da einfach eine ganz normale Funktion und du holst dir dann den Zeiger auf die Instanz ja selbst (mit GetWindowLong). Bei Bedarf kannst du diese Funktion ja friend in CWindow deklarieren, dann hast du genau die gleichen Möglichkeiten, wie wenn das eine Memberfunktion wäre.

    btw:
    Ich mache das selbst auch in etwa so.



  • So, konnte mich leider erst jetzt wieder damit beschäftigen, ich hoffe mal das fällt jetzt nicht schon unter thread necromancy 😉

    Also erstmal danke für deine Antwort, hab mir diese Friendfunktionen jetzt mal angeschaut, eigentlich eine interessante Sache. Zwar kann ich damit jetzt auf private Felder zugreifen, aber das Problem mit der Vererbung bleibt das gleiche. Langsam denke ich mir es ist doch praktischer das ganze per Switch und festen Methoden zu machen... Oder übersehe ich da irgendwas?



  • Ich weiss jetzt nicht, was du mit der Vererbung meinst..

    Aber das hier:

    typedef long (CWindow::* tyMessageHandler)(CWindow &, HWND, long, long);
    

    Machst du besser so:

    typedef long (*tyMessageHandler)(CWindow &, HWND, long, long);
    

    Also eine normale Funktion, die long zurückgibt und 4 Parameter nimmt.

    Eine passende Funktion wäre z.B das hier:

    long do_something (CWindow& w, HWND hw, long l, long l2 ){ return 0;}
    

    oder aber auch das hier:

    struct foo
    {
     static long do_something (CWindow& w, HWND hw, long l, long l2 ){ return 0; }
    }
    

    Das static bewirkt, dass die Funktion nicht von einer Instanz abhängt.

    Der Aufruf sollte dann so klappen, wie du ihn vorgeschlagen hast:

    return (it->second)(*wnd, hwnd, wparam, lparam);
    

    Das, was ich mit dem friend meinte war lediglich, dass, wenn du eine solche freie Funktion hast keinen Zugriff auf die privaten Member der Klasse hast und das könntest du mit friend lösen. (oder gleich die statische Variante innerhalb der Klasse benutzen).



  • Du könntest dir auch std::tr1::function und std::tr1::bind anschauen, damit sind Funktionszeiger ein Kinderspiel.

    Ansonsten denke ich aber, dass virtuelle Funktionen (etwa virtual bool onClose() ) mit switch-Kaskade in der WndProc einige Vorteile haben, so kannst du auch jeder Nachricht eine eigene Signatur mitgeben: WM_CLOSE braucht (afair) keine Parameter, beim Handler für WM_COMMAND kannst du gleich die "entpackten" und entsprechend typisierten Parameter mitgeben.



  • @Drakon: Ja das habe ich bereits alles gemacht, so ist es ja eigentlich auch im Tutorial gelöst. Mit Vererbung meine ich, dass ich z.B. nicht jedes mal DestroyWindow() aufrufen muss, sondern einmal einen WM_CLOSE Handler implementiere und den an alle abgeleiteten Klassen erben - trotzdem aber weitere Funktionalität hinzufügen können. Das wäre bei einer externen Funktion natürlich nicht möglich.

    @Badestrand: Ok danke ich sehs mir mal an, aber ich denke du hast recht bezüglich dem Switch.



  • Sooo, also ich hab jetzt mehrere Stunden versucht das ganze mit einer std::tr1::function zum laufen zu kriegen - leider erfolglos.

    typedef std::tr1::function<long(CWindow &, HWND, long, long)> tyMessageHandler;
    

    Auch hier habe ich keinen Weg finden können eine Memberfunktion zuzuweisen - oder hast du das anders gemeint?



  • spline schrieb:

    Methode zurückgeben

    Soweit ich weiß, bekommst du nur einen Gutschein, aber kein Geld, wenn du die Methode zurück gibts.



  • Ich sehe dein Problem ehrlichgesagt nicht ganz. Mach mal ein kleines Programm, wie du das gerne haben möchtest, aber ansonsten komplett ist.


Anmelden zum Antworten