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

Как вы передаете указатель на функцию-член?

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

Вот копия класса, передающего функцию-член:

class testMenu : public MenuScreen{
public:

bool draw;

MenuButton<testMenu> x;

testMenu():MenuScreen("testMenu"){
    x.SetButton(100,100,TEXT("buttonNormal.png"),TEXT("buttonHover.png"),TEXT("buttonPressed.png"),100,40,&this->test2);

    draw = false;
}

void test2(){
    draw = true;
}
};

Функция x.SetButton(...) содержится в другом классе, где "объект" является шаблоном.

void SetButton(int xPos, int yPos, LPCWSTR normalFilePath, LPCWSTR hoverFilePath, LPCWSTR pressedFilePath, int Width, int Height, void (object::*ButtonFunc)()) {

    BUTTON::SetButton(xPos, yPos, normalFilePath, hoverFilePath, pressedFilePath, Width, Height);

    this->ButtonFunc = &ButtonFunc;
}

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

4b9b3361

Ответ 1

Чтобы вызвать функцию-член по указателю, вам понадобятся две вещи: указатель на объект и указатель на функцию. Вам нужно как в MenuButton::SetButton()

template <class object>
void MenuButton::SetButton(int xPos, int yPos, LPCWSTR normalFilePath,
        LPCWSTR hoverFilePath, LPCWSTR pressedFilePath,
        int Width, int Height, object *ButtonObj, void (object::*ButtonFunc)())
{
  BUTTON::SetButton(xPos, yPos, normalFilePath, hoverFilePath, pressedFilePath, Width, Height);

  this->ButtonObj = ButtonObj;
  this->ButtonFunc = ButtonFunc;
}

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

((ButtonObj)->*(ButtonFunc))();

Не забудьте передать указатель на свой объект на MenuButton::SetButton():

testMenu::testMenu()
  :MenuScreen("testMenu")
{
  x.SetButton(100,100,TEXT("buttonNormal.png"), TEXT("buttonHover.png"),
        TEXT("buttonPressed.png"), 100, 40, this, test2);
  draw = false;
}

Ответ 3

Я знаю, что это довольно старая тема. Но есть элегантный способ справиться с этим с помощью С++ 11

#include <functional>

объявите указатель на функцию следующим образом

typedef std::function<int(int,int) > Max;

объявите свою функцию, чтобы передать эту вещь в

void SetHandler(Max Handler);

предположим, что вы передаете ему нормальную функцию, вы можете использовать его как обычный

SetHandler(&some function);

предположим, что у вас есть функция-член

class test{
public:
  int GetMax(int a, int b);
...
}

в вашем коде вы можете передать его с помощью std::placeholders, как этот

test t;
Max Handler = std::bind(&test::GetMax,&t,std::placeholders::_1,std::placeholders::_2);
some object.SetHandler(Handler);

Ответ 4

Не лучше ли вам использовать стандартную OO. Определите контракт (виртуальный класс) и реализуйте его в своем собственном классе, а затем просто передайте ссылку на свой собственный класс и позвольте получателю вызвать контрактную функцию.

Используя ваш пример (я переименовал метод 'test2' в 'buttonAction'):

class ButtonContract
{
  public:
    virtual void buttonAction();
}


class testMenu : public MenuScreen, public virtual ButtonContract
{
  public:
    bool draw;
    MenuButton<testMenu> x;

    testMenu():MenuScreen("testMenu")
    {
      x.SetButton(100,100,TEXT("buttonNormal.png"), 
              TEXT("buttonHover.png"), 
              TEXT("buttonPressed.png"), 
              100, 40, &this);
      draw = false;
    }

    //Implementation of the ButtonContract method!
    void buttonAction()
    {
      draw = true;
    }
};

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

Ответ 5

В редком случае, когда вы разрабатываете Borland С++ Builder и не против писать код, специфичный для этой среды разработки (то есть код, который не будет работать с другими компиляторами на С++), вы можете использовать ключевое слово __closure. Я нашел небольшую статью о закрытии С++ Builder. Они предназначены в первую очередь для использования с Borland VCL.

Ответ 6

Другие говорили вам, как это сделать правильно. Но я удивлен, что никто не сказал вам, что этот код действительно опасен:

this->ButtonFunc = &ButtonFunc;

Так как ButtonFunc является параметром, он выйдет из области действия, когда функция вернется. Вы берете его адрес. Вы получите значение типа void (object::**ButtonFunc)() (указатель на указатель на функцию-член) и назначьте его этому → ButtonFunc. В то время, когда вы попытаетесь использовать this- > ButtonFunc, вы попытаетесь получить доступ к хранилищу локального параметра (теперь уже не существующего), и ваша программа, вероятно, сбой.

Я согласен с решением Commodore. Но вы должны изменить свою линию на

((ButtonObj)->*(ButtonFunc))();

поскольку ButtonObj является указателем на объект.