Question

J'essaie d'écrire un système d'événements de rappel dans DirectX9. J'essaie d'utiliser des pointeurs de fonction de méthode pour déclencher des événements en effectuant des clics de souris; mais j'ai des problèmes. Mon jeu utilise un gestionnaire de jeu pour gérer le rendu. Tous mes domaines de jeux sont dérivés d'une classe de base AbstractGameState.

J'ai un objet sprite avec cette méthode spécifique:

m_NewGameSprite->OnClick(this, &MainMenuState::StartGame);

MainMenuState est le jeu actuel dans lequel se trouve mon jeu et StartGame est une méthode vide faisant partie de cette classe. J'aimerais stocker le pointeur de fonction dans une variable de ma classe d'images-objets afin de pouvoir l'exécuter lorsque l'utilisateur clique dessus.

template <typename T>
void OnClick(GameState* LinkedState, void (T::*EventPointer)())
{
    m_LinkedGameState = LinkedState;
    m_EventPointer = EventPointer; // <- Doesnt compile
}

J'ai essayé d'abaisser le pointeur, mais cela n'a pas vraiment fonctionné.

Ma classe de sprites contient également ces deux variables

void                (GameState::*m_EventPointer)();
GameState*          m_LinkedGameState;

Toute aide serait appréciée

Était-ce utile?

La solution

Je ne sais pas vraiment pourquoi votre mission ne fonctionne pas. Nul doute que nous serons bientôt là pour vous expliquer pourquoi. Boost.Function est un superbe générique générique typesafe. et un objet fonction standard pouvant remplacer les pointeurs de fonction dans presque toutes les circonstances. Je voudrais faire ceci:

typedef boost::function0<void> Event;
Event m_Event;

Notez que la classe d'événements encapsule désormais l'état de l'appel de fonction, y compris l'objet sur lequel vous souhaitez l'appeler. Normalement, vous utilisez également Boost.Bind pour créer un fermeture, mais vous pouvez facilement vous lier à une fonction libre ou à un autre objet fonction.

void OnClick(Event &event)
{
  m_Event=event;
}

Appelez ça comme ça:

OnClick(boost::bind(&MainMenuState::StartGame, this));

Avec ce schéma, vous n'avez pas vraiment besoin de stocker l'état & "; l'état du jeu lié &"; - ceci est encapsulé dans l'objet event.

Autres conseils

J'ai eu un problème très similaire. Si je lis ceci correctement, vous essayez d'écrire un système presque comme un ActionEvent en Java. Ce qui pourrait ressembler à ceci:

Component.addActionListener( new ActionEventListener( new ActionEvent(
            public void execute() { /* Component clicked Do Something */ } )));

En C ++, il existe une procédure très similaire à celle décrite ci-dessous.

À mon avis, c'est beaucoup mieux car vous pouvez réellement réutiliser les appels de méthode et les modifier à volonté, ce qui vous donne beaucoup plus de flexibilité.

Event.hpp

#pragma once

class Event 
{
    public:
        Event(void) { }
        ~Event(void) { }

    public:
        //Stores a function to callback. Example shown in Main.cpp
        void operator += (void (*callback)())
        {
            this->callback = callback;
        }

        //Executes our stored call back method at any given time.
        void execute(void)
        {
            callback();
        }

        //Variable of type VOID* -> This is a function which is stored + executed.
        private:
            void (*callback)();
};

Main.cpp

#include <iostream>
#include "Event.hpp"

using namespace std;

void print(void)
{
    cout << "Hello This Works" << endl;
}

void print2(void)
{
    cout << "Success again!" << endl;
}

int main()
{
    Event task_event;
    task_event += print;
    task_event.execute();
    task_event += print2;
    task_event.execute();
    system("pause");
    return 0;
}

Le problème ici est que StartGame ne peut être appelé avec aucune instance GameState à l'aide de son paramètre this. Il ne peut être appelé qu'avec un paramètre MainMenuState de type void (GameState::*)().

Pour que Callback * pointe vers une méthode définie dans <=>, celle-ci doit être une méthode virtuelle également définie dans <=>.

Je recommanderais plutôt que d'essayer de stocker un pointeur de fonction membre de stocker un objet de commande & "; &"; (ou foncteur) pointeur, en utilisant quelque chose comme:

class Callback
{
public:
    virtual void Execute() = 0;
};

Et ensuite, définir une implémentation comme ceci:

template <typename TClass>
class MemberCallback : public Callback
{
public:

    MemberCallBack(TClass * pThis, void (TClass::*pFunc)() )
    {
        m_pThis = pThis;
        m_pFunc = pFunc;
    }
    void Execute()
    {
        m_pThis->*m_pFunc();
    }

private:
    TClass * m_pThis;
    void (TClass::*m_pFunc)();
};

Vous pouvez ensuite définir un membre de type <=>.

Pourquoi utilisez-vous une fonction de modèle ici? OnClick ne compilera pas et ne fonctionnera pas pour les valeurs T autres que GameState.

Cependant, dans cette situation, je n’utiliserais généralement pas de pointeur sur une fonction membre. Je créerais une fonction objet , surchargeant operator(), et les passerais à la place. C’est mieux: la syntaxe est plus claire et vous pouvez stocker certains états dans l’objet fonction si vous estimez que vous en avez besoin.

Vous devez prendre le paramètre comme un:

void (GameState::*EventPointer)()

Parce qu’une fois un pointeur, il ne peut pas être downcast comme ça (il n’a aucune information quant à savoir si le même pointeur existe dans la classe de base). Les fonctions devront être sur GameState pour que cela fonctionne (potentiellement virtuel)

Cependant! Étant donné que vous effectuez des callbacks (essentiellement un motif observateur), vous pouvez jeter un long regard sur boost :: signaux . Il fera tout cela (et plus). Vous n'êtes pas obligé d'ajouter des fonctions à GameState.

class Foo {
 // ...
 template <typename T>
 boost::signals::connection OnClick(const boost::function<void ()>& func)
 {
    return sig.connect(func);
 }

 void FireClick() { sig_(); }
private:
  boost::signal<void ()> sig_;
};

int this_will_be_called() { }

Foo f = // ...;

f.OnClick(boost::bind(&this_will_be_called));
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top