Нестандартный синтаксис - используйте & для создания указателя на член: указатель функции C ++ на член - PullRequest
1 голос
/ 04 мая 2020

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

У меня также есть Класс двигателя, который управляет рисованием моего спирографа и кнопок GUI.

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

Ошибка возникает, когда я пытаюсь создать кнопка с указателем на функцию из класса Engine.

Вот в двух словах проблема, предложенная Фрэнком в комментариях (спасибо)

    class Engine;
typedef void(Engine::*enginefunc)(void);

class Engine
{
    void cb();
    void register_callback(enginefunc ptr);

    void foo() {
        register_callback(cb);
    }
};

Вот мой класс двигателя:

Engine.h

class Engine : public GUI
{
private:
//....
public:
    Engine(sf::Vector2f* mousepos);
    //...
//...inherited a function from GUI called addbutton.

};
Engine::Engine(sf::Vector2f* mousepos)
    :GUI(mousepos)
{   


//THIS IS THE LINE WHICH PRODUCES THE ERROR. I AM TRYING TO PASS THE CHANGE POINT FUNCTION INTO THE GUI BUTTON.
        addbutton(sf::Vector2f{ 100,50 }, sf::Vector2f{ 200,100 }, "Button", sf::Color::Red, sf::Color::Blue, changepoint); 
    }

Вот GUI .h (Содержит функцию addbutton, которая вызывает ошибку)

class Engine;

typedef void(Engine::* enginefunc)(void);

class GUI : public sf::Drawable
{
private:    
    //...
public:

    GUI(sf::Vector2f* mousepos);
    void addbutton(const sf::Vector2f& position, const sf::Vector2f& dimension, const std::string& text, sf::Color initcolor, sf::Color highlightcolor, enginefunc ptr);
    //other member funcs..
};

Вот GUI :: функция addbutton

void GUI::addbutton(const sf::Vector2f& pos, const sf::Vector2f& size, const std::string& text, sf::Color before, sf::Color after, enginefunc ptr)
{
    buttons.emplace_back(pos, size, text, before, after, ptr);
}

Итак, функция addbutton создает класс GUIButton, в котором хранится функция ptr. Когда кнопка нажата, указатель этой функции вызывается через std :: invoke.

Вот мой GUIButton.h

class Engine;
typedef void(Engine::*enginefunc)(void);
class GUIButton :  public sf::RectangleShape
{
public:
    GUIButton(const sf::Vector2f& position, const sf::Vector2f& size, const std::string& text, sf::Color initcolor, sf::Color highlightcolor, enginefunc ptr);
    void action(Engine& e);
    //other members...
private:
//other members...
    enginefunc actionptr;
};

Как вы можете видеть, enginefun c GUIButton: : actionptr - это указатель на функцию, который будет действовать при нажатии кнопки.

Вот функция GUIButton :: action (), которая вызывает функцию:

    void GUIButton::action(Engine& e)
{
    if (actionptr != nullptr)
    {
        std::invoke(actionptr, e);
    }
}

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

Есть предложения?

1 Ответ

1 голос
/ 04 мая 2020

Вы должны просто использовать вместо std::function. В этом случае передовые практики призывают использовать лямбду для привязки this.

Эквивалент вашего кода:

class Engine;
typedef void(Engine::*enginefunc)(void);

class Engine
{
    Engine();
    void changepoint();
    void addbutton(enginefunc ptr);
};

Engine::Engine() {
    addbutton(changepoint);
}

Становится:

class Engine
{
    Engine();
    void changepoint();
    void addbutton(std::function<void()> ptr);
};

Engine::Engine() {
    addbutton([this](){changepoint();});
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...