Pergunta

Digamos que eu tenha:

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

Isso é bom, desde que a função que desejo usar para renderizar seja uma função ou um static função de membro:

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

No entanto, eu realmente quero poder usar um método de classe também, já que na maioria dos casos a função de renderização desejará acessar variáveis ​​de membro e prefiro não tornar a instância da classe global, por exemplo.

Render(MainMenu->Render);

No entanto, eu realmente não tenho ideia de como fazer isso e ainda permito funções e static funções de membro a serem usadas.

Foi útil?

Solução

Há muitas maneiras de esfolar esse gato, incluindo modelos.Meu favorito é Função Boost pois descobri que é o mais flexível no longo prazo.Leia também em Boost.bind para ligação a funções-membro, bem como muitos outros truques.

Ficaria assim:

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

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

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

Outras dicas

Você pode fazer uma função wrapper void Wrap(T *t) isso só chama t->Call() e tem Render tome tal função junto com um objeto.Aquilo é:

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

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

Fiz isso uma vez definindo uma função global "Call" que aceita um ponteiro para sua instância como membro

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

Então a renderização se torna:

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

E sua chamada para renderizar é:

Render(CallRender, &MainMenu);

Eu sei que é feio, mas funcionou para mim (eu estava usando pthreads)

Você não pode chamar uma função membro a partir de um ponteiro, a menos que também tenha uma referência ao objeto.Por exemplo:

((object).*(ptrToMember))

Portanto, você não conseguirá isso sem alterar a assinatura do seu método de renderização. Esse Este artigo explica por que isso geralmente é uma má ideia.

Uma maneira melhor seria definir uma interface "Renderer" que suas classes que possuem métodos de renderização possam implementar e que esse seja o tipo de parâmetro do seu método Render principal.Você poderia então escrever uma implementação "StaticCaller" para suportar a chamada de seus métodos estáticos por referência.

por exemplo (meu C++ está realmente enferrujado, também não compilei).



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

Tudo isso é bastante clichê, mas deve proporcionar mais legibilidade.

Você pode declarar um ponteiro de função para uma função membro da classe T usando:

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

E invoque-o como:

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

Extrapolar isso para um sistema de curry útil com argumentos variáveis, tipos, valores de retorno, etc., é monótono e irritante.Ouvi coisas boas sobre a biblioteca de reforço mencionada acima, então recomendo dar uma olhada nisso antes de fazer qualquer coisa drástica.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top