C ++函数指针和类

时间:2020-03-05 18:52:42  来源:igfitidea点击:

说我有:

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

只要我要渲染的函数是一个函数或者一个"静态"成员函数,就可以了:

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

但是,我真的希望也能够使用类方法,因为在大多数情况下渲染功能将要访问成员变量,而Id则不希望将类实例设置为全局实例,例如

Render(MainMenu->Render);

但是我真的不知道该怎么做,仍然允许使用函数和static成员函数。

解决方案

回答

我们可以创建一个包装函数void Wrap(T * t),该包装函数仅调用t-> Call(),并使Render与对象一起使用此类函数。那是:

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

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

回答

有很多方法可以为这只猫蒙皮,包括模板。我最喜欢的是Boost.function,因为从长远来看,我发现它是最灵活的。还可以阅读Boost.bind上的绑定成员函数以及许多其他技巧。

它看起来像这样:

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

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

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

回答

我通过定义一个全局函数" Call"来做到这一点,该函数接受一个指向实例的指针作为成员

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

因此渲染变为:

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

我们对render的调用是:

Render(CallRender, &MainMenu);

我知道这很丑陋,但是为我工作(我在使用pthreads)

回答

回答

关于C ++常见问题解答:指向成员的指针又如何呢?

回答

我们可以使用以下方法声明指向类T的成员函数的函数指针:

((object).*(ptrToMember))

So you won't be able to acheive this without changing the signature of your render method.  This article explains why this is generally a bad idea.

A better way might be to define a "Renderer" interface which your classes that have render methods can implement and have that be the parameter type of your main Render method.  You could then write a "StaticCaller" implementation to support the calling of your static methods by reference.

eg (My C++ is really rusty, I haven't compiled this either).

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

并将其调用为:

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

用可变的参数,类型,返回值等将其外推到有用的currying系统中是单调且令人讨厌的。我已经听说了有关上述Boost库的好消息,因此建议我们在进行任何大动作之前先进行研究。

代码数量不匹配