Question

Disons que j'ai :

void Render(void(*Call)())
{
    D3dDevice->BeginScene();
    Call();
    D3dDevice->EndScene();
    D3dDevice->Present(0,0,0,0);
}

C'est très bien tant que la fonction que je souhaite utiliser pour le rendu est une fonction ou un static fonction membre :

Render(MainMenuRender);
Render(MainMenu::Render);

Cependant, je veux vraiment pouvoir également utiliser une méthode de classe car dans la plupart des cas, la fonction de rendu voudra accéder aux variables membres, et je préfère ne pas rendre l'instance de classe globale, par exemple.

Render(MainMenu->Render);

Cependant, je n'ai vraiment aucune idée de comment faire cela, et j'autorise toujours les fonctions et static fonctions membres à utiliser.

Était-ce utile?

La solution

Il existe de nombreuses façons de dépecer ce chat, y compris des modèles.Mon favori est Fonction Boost car j'ai trouvé que c'était le plus flexible à long terme.Lisez également sur Boost.bind pour la liaison aux fonctions membres ainsi que de nombreuses autres astuces.

Cela ressemblerait à ceci :

#include <boost/bind.hpp>
#include <boost/function.hpp>

void Render(boost::function0<void> Call)
{
    // as before...
}

Render(boost::bind(&MainMenu::Render, myMainMenuInstance));

Autres conseils

Vous pouvez créer une fonction wrapper void Wrap(T *t) ça appelle juste t->Call() et avoir Render prendre une telle fonction avec un objet.C'est-à-dire:

void Wrap(T *t)
{
  t->Call();
}

void Render(void (*f)(T *), T *t)
{
  ...
  f(t);
  ...
}

Quoi à propos de quoi FAQ C++ :Pointeurs vers les membres dit?

Je l'ai fait une fois en définissant une fonction globale "Call" qui accepte un pointeur vers votre instance en tant que membre

void CallRender(myclass *Instance)
{
  Instance->Render();
}

Le rendu devient donc :

void Render(void (*Call)(myclass*), myclass* Instance)
{
  ...
  Call(Instance);
  ...
}

Et votre appel à render est :

Render(CallRender, &MainMenu);

Je sais que c'est moche, mais ça a fonctionné pour moi (j'utilisais pthreads)

Vous ne pouvez pas appeler une fonction membre à partir d’un pointeur à moins que vous n’ayez également une référence à l’objet.Par exemple:

((object).*(ptrToMember))

Vous ne pourrez donc pas y parvenir sans changer la signature de votre méthode de rendu. Ce L'article explique pourquoi c'est généralement une mauvaise idée.

Une meilleure façon pourrait être de définir une interface "Renderer" que vos classes qui ont des méthodes de rendu peuvent implémenter et que ce soit le type de paramètre de votre méthode de rendu principale.Vous pouvez ensuite écrire une implémentation "StaticCaller" pour prendre en charge l'appel de vos méthodes statiques par référence.

par exemple (Mon C++ est vraiment rouillé, je ne l'ai pas compilé non plus).



void Render(IRenderer *Renderer)
{
    D3dDevice->BeginScene();
    Renderer->Render();
    D3dDevice->EndScene();
    D3dDevice->Present(0,0,0,0);
}

// The "interface"
public class IRenderer 
{
public:
    virtual void Render();
};

public class StaticCaller: public IRenderer
{
    void (*Call)();
public:

    StaticCaller((*Call)())
    {
        this->Call = Call;
    }

    void Render()
    {
        Call();
    }
};

Tout cela est assez passe-partout mais cela devrait permettre plus de lisibilité.

Vous pouvez déclarer un pointeur de fonction vers une fonction membre de la classe T en utilisant :

typedef void (T::*FUNCTIONPOINTERTYPE)(args..)
FUNCTIONPOINTERTYPE function;

Et invoquez-le comme :

T* t;
FUNCTIONPOINTERTYPE function;
(t->*function)(args..);

Extrapoler cela dans un système de curry utile avec des arguments variables, des types, des valeurs de retour, etc., est monotone et ennuyeux.J'ai entendu de bonnes choses à propos de la bibliothèque boost susmentionnée, je vous recommande donc de l'examiner avant de faire quoi que ce soit de radical.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top