Подтвердить что ты не робот

Указатели и классы функций С++

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

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

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

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

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

Render(MainMenu->Render);

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

4b9b3361

Ответ 1

Существует много способов скинуть этот кот, включая шаблоны. Мой любимый 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));

Ответ 2

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

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

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

Ответ 4

Я сделал это один раз, указав глобальную функцию "Вызов", которая принимает указатель на ваш вклад в качестве члена

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

Таким образом, рендер становится:

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

И ваш призыв к рендерингу:

Render(CallRender, &MainMenu);

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

Ответ 5

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

((object).*(ptrToMember))

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

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

eg (Мой С++ действительно ржавый, я тоже не скомпилировал это).



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

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

Ответ 6

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

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

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

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

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