que - Punteros y clases de función C++
que es un puntero en c++ (6)
Hay muchas maneras de despellejar a este gato, incluidas las plantillas. Mi favorito es la función Boost, ya que considero que es la más flexible a largo plazo. Lee también en Boost.bind para vincular las funciones de miembro y muchos otros trucos.
Se vería así:
#include <boost/bind.hpp>
#include <boost/function.hpp>
void Render(boost::function0<void> Call)
{
// as before...
}
Render(boost::bind(&MainMenu::Render, myMainMenuInstance));
Digamos que tengo:
void Render(void(*Call)())
{
D3dDevice->BeginScene();
Call();
D3dDevice->EndScene();
D3dDevice->Present(0,0,0,0);
}
Esto está bien siempre que la función que deseo usar para representar sea una función o una función miembro static
:
Render(MainMenuRender);
Render(MainMenu::Render);
Sin embargo, realmente quiero poder utilizar un método de clase también, ya que en la mayoría de los casos la función de renderización querrá acceder a las variables miembro, y Id no hará que la instancia de clase sea global, por ejemplo
Render(MainMenu->Render);
Sin embargo, realmente no tengo ni idea de cómo hacer esto, y todavía me permiten usar funciones y funciones de miembros static
.
Lo hice una vez al definir una función global "Llamar" que acepta un puntero a su integridad como miembro
void CallRender(myclass *Instance)
{
Instance->Render();
}
Entonces el render se convierte en:
void Render(void (*Call)(myclass*), myclass* Instance)
{
...
Call(Instance);
...
}
Y tu llamada a render es:
Render(CallRender, &MainMenu);
Sé que es feo, pero funcionó para mí (estaba usando pthreads)
No puede llamar a una función miembro desde un puntero a menos que también tenga una referencia al objeto. Por ejemplo:
((object).*(ptrToMember))
Por lo tanto, no podrá lograr esto sin cambiar la firma de su método de representación. Este artículo explica por qué esto generalmente es una mala idea.
Una mejor manera podría ser definir una interfaz "Renderer" que tus clases que tienen métodos de renderización puedan implementar y que sea el tipo de parámetro de tu método Render principal. A continuación, puede escribir una implementación de "StaticCaller" para apoyar la llamada de sus métodos estáticos por referencia.
por ejemplo, (Mi C ++ está muy oxidado, tampoco lo he compilado).
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();
}
};
Todo esto es bastante repetitivo, pero debería ser más legible.
Puede hacer que una función de envoltura void Wrap(T *t)
que simplemente llama a t->Call()
y que Render
tome dicha función junto con un objeto. Es decir:
void Wrap(T *t)
{
t->Call();
}
void Render(void (*f)(T *), T *t)
{
...
f(t);
...
}
¿Qué pasa con las preguntas frecuentes de C ++: dice Punteros a los miembros ?
Puede declarar un puntero de función a una función miembro de clase T usando:
typedef void (T::*FUNCTIONPOINTERTYPE)(args..)
FUNCTIONPOINTERTYPE function;
E invocarlo como:
T* t;
FUNCTIONPOINTERTYPE function;
(t->*function)(args..);
Extrapolar esto en un sistema de currying útil con argumentos variables, tipos, valores de retorno, etc., es monótono y molesto. He oído cosas buenas sobre la biblioteca de impulso antes mencionada, por lo que recomiendo examinar eso antes de hacer algo drástico.