Вопрос

Скажем, у меня есть:

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

Это нормально, если функция, которую я хочу использовать для рендеринга, является функцией или static функция-член:

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

Однако я действительно хочу иметь возможность использовать метод класса, поскольку в большинстве случаев функция рендеринга захочет получить доступ к переменным-членам, и я бы предпочел не делать экземпляр класса глобальным, например

Render(MainMenu->Render);

Однако я действительно понятия не имею, как это сделать, и все еще разрешаю функции и static функции-члены, которые будут использоваться.

Это было полезно?

Решение

Способов шкурить этого кота очень много, в том числе и шаблоны.Мой любимый Boost.функция поскольку я считаю, что это наиболее гибко в долгосрочной перспективе.Также почитайте Boost.bind для привязки к функциям-членам, а также для многих других трюков.

Это будет выглядеть так:

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

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

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

Другие советы

Вы можете сделать функцию-обертку void Wrap(T *t) это просто звонит t->Call() и имеют Render возьмите такую ​​функцию вместе с объектом.То есть:

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

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

Однажды я сделал это, определив глобальную функцию «Вызов», которая принимает указатель на ваш вход в качестве члена.

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

Итак, рендер становится:

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

И ваш вызов для рендеринга:

Render(CallRender, &MainMenu);

Я знаю, что это некрасиво, но у меня сработало (я использовал pthreads)

Вы не можете вызвать функцию-член из указателя, если у вас также нет ссылки на объект.Например:

((object).*(ptrToMember))

Таким образом, вы не сможете добиться этого, не изменив сигнатуру вашего метода рендеринга. Этот статья объясняет, почему это вообще плохая идея.

Лучшим способом может быть определение интерфейса «Renderer», который могут реализовать ваши классы, имеющие методы рендеринга, и сделать его типом параметра вашего основного метода рендеринга.Затем вы можете написать реализацию «StaticCaller» для поддержки вызова статических методов по ссылке.

например (Мой C++ действительно заржавел, я его тоже не компилировал).



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

Все это довольно шаблонно, но это должно сделать текст более читабельным.

Вы можете объявить указатель на функцию-член класса T, используя:

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

И вызовите его как:

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

Экстраполяция этого в полезную систему каррирования с переменными аргументами, типами, возвращаемыми значениями и т. д. монотонна и раздражает.Я слышал хорошие отзывы о вышеупомянутой библиотеке повышения, поэтому рекомендую изучить ее, прежде чем предпринимать какие-либо радикальные действия.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top