Domanda

Diciamo che ho:

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

Questo va bene purché la funzione che voglio usare per il rendering sia una funzione o a static funzione membro:

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

Tuttavia, voglio davvero essere in grado di utilizzare anche un metodo di classe poiché nella maggior parte dei casi la funzione di rendering vorrà accedere alle variabili membro e preferirei non rendere globale l'istanza della classe, ad es.

Render(MainMenu->Render);

Tuttavia non ho davvero idea di come farlo e consento comunque le funzioni e static funzioni membro da utilizzare.

È stato utile?

Soluzione

Esistono molti modi per scuoiare questo gatto, inclusi i modelli.Il mio preferito è Funzione.Boost poiché ho trovato che sia il più flessibile a lungo termine.Leggi anche su Boost.bind per l'associazione alle funzioni membro e molti altri trucchi.

Sarebbe simile a questo:

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

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

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

Altri suggerimenti

Puoi creare una funzione wrapper void Wrap(T *t) quello chiama e basta t->Call() e avere Render prendi una tale funzione insieme a un oggetto.Questo è:

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

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

L'ho fatto una volta definendo una funzione globale "Call" che accetta un puntatore alla tua istanza come membro

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

Quindi il rendering diventa:

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

E la tua chiamata per il rendering è:

Render(CallRender, &MainMenu);

So che è brutto, ma ha funzionato per me (stavo usando pthreads)

Non è possibile chiamare una funzione membro da un puntatore a meno che non si abbia anche un riferimento all'oggetto.Per esempio:

((object).*(ptrToMember))

Quindi non sarai in grado di raggiungere questo obiettivo senza modificare la firma del tuo metodo di rendering. Questo l'articolo spiega perché questa è generalmente una cattiva idea.

Un modo migliore potrebbe essere quello di definire un'interfaccia "Renderer" che le tue classi che hanno metodi di rendering possono implementare e che sia il tipo di parametro del tuo metodo Render principale.Potresti quindi scrivere un'implementazione "StaticCaller" per supportare la chiamata dei tuoi metodi statici per riferimento.

ad esempio (il mio C++ è davvero arrugginito, non ho compilato neanche questo).



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();
    }
};

Tutto questo è piuttosto standard ma dovrebbe garantire una maggiore leggibilità.

È possibile dichiarare un puntatore a funzione a una funzione membro della classe T utilizzando:

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

E invocarlo come:

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

Estrapolarlo in un utile sistema di currying con argomenti variabili, tipi, valori restituiti, ecc. È monotono e fastidioso.Ho sentito parlare bene della suddetta libreria di boost, quindi consiglierei di esaminarla prima di fare qualcosa di drastico.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top