Вопрос

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

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

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(...) содержится в другом классе, где "object" - это шаблон.

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

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

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

Решение

Чтобы вызвать функцию-член по указателю, вам нужны две вещи:Указатель на объект и указатель на функцию.Вам нужно и то, и другое в 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;
}

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

Я бы настоятельно рекомендовал boost::bind и boost::function для чего-нибудь подобного.

Видишь Передайте и вызовите функцию-член (boost::bind / boost::function?)

Я знаю, что это довольно старая тема.Но есть элегантный способ справиться с этим с помощью c ++ 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);

Не лучше ли было бы вам использовать стандартный 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;
    }
};

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

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

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

this->ButtonFunc = &ButtonFunc;

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

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

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

поскольку ButtonObj является указатель возражать.

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