将函数指针保存在 class 的成员中

Saving a function pointer in member of a class

我正在制作一个包含菜单项的菜单栏。我想要包含菜单栏的 window 来决定菜单项的行为。所以我希望 window 将一个函数传递给菜单项。

我最好的尝试是得到这个错误:

error: no matching function for call to 'MenuItem::setBehaviour(void (MyWindow::*)())'

这里是MenuItem.h:

class MenuItem{
public:
    typedef void (sf::RenderWindow::*function_type)();

    MenuItem(sf::RenderWindow* win); // window that holds the menu bar

    void setBehaviour(function_type f); // I want to be able to change the behaviour
                                        // to reuse the menu item
    void action(); // use the function

private:
    sf::RenderWindow* m_window;
    function_type     m_function;
};

MenuItem.cpp

MenuItem::MenuItem(sf::RenderWindow* win) : m_window(win)
{
    //ctor
}

void MenuItem::setBehaviour(function_type f)
{
     m_function = f;
}

void MenuItem::action()
{
    (m_window->*m_function)();
}

添加菜单栏的window:

class MyWindow : public sf::RenderWindow
{
    //...
    void close();
};

和 window 的 cpp 文件:

MyWindow::MyWindow() : sf::RenderWindow(...)
{
    //...
    MenuItem item(this);
    item.setBehaviour(&MyWindow::close); // error!
    //...
}

//...

void MyWindow::close()
{
    this->close();
}

您可以尝试解决的问题是使 MenuItem 成为模板 class:

template<typename RenderWindow>
class MenuItem{
public:
    typedef void (RenderWindow::*function_type)();

    MenuItem::MenuItem(RenderWindow* win) 
    : m_window(win) {
        std::static_assert(
            std::is_base_of<sf::RenderWindow,RenderWindow>()
                           ,"RenderWindow must be derived from sf::RenderWindow.");
    }

    void setBehaviour(function_type f) {
        m_function = f;
    }

    void action() {
        m_window->*m_function)();
    }

private:
    RenderWindow*     m_window;
    function_type     m_function;
};

完全省略 MenuItem.cpp 文件。

您可以像

一样实例化和访问 MenuItem
MyWindow myWindow;
MenuItem<MyWindow> closeWindow(myWindow);
menuItem.setBehavior(MyWindow::close);

// ...
menuItem.action();

然后。

你可以使用 std::function

// MenuItem.h
#include <functional>

class MenuItem
{
    public:
        using function_type = std::function<void()>;
        auto setBehaviour(function_type f) -> void;
        auto action() -> void;

    private:
        function_type m_function;
};

// MenuItem.cpp
auto MenuItem::setBehaviour(function_type f) -> void
{
    m_function = f;
}

auto MenuItem::action() -> void
{
    m_function();
}

// MyWindow.cpp
#include <functional>

MyWindow::MyWindow() : sf::RenderWindow(...)
{
    MenuItem item(this);
    item.setBehaviour(std::bind(&MyWindow::close, this));
}

auto MyWindow::close() -> void
{
    // do something
}

给出的两个答案让我有点头疼。我花了一些时间查看 Jan 的 std::function 并在此过程中学到了更多东西。这是我做错的地方:

MenuItem 的功能将来自 MyWindow,而不是 sf::RenderWindow,因此我需要转发声明 MyWindow 并将所有 sf::RenderWindow 更改为 MyWindow。

class MyWindow; // fix: forward declaration
class MenuItem{
    public:

    typedef void (MyWindow::*function_type)(); // fix

    MenuItem(MyWindow* win); // fix

    void setBehaviour(function_type f);

    void action();

private:
    MyWindow* m_window; // fix
    function_type     m_function;
};

MenuItem.cpp

MenuItem::MenuItem(MyWindow* win) : m_window(win) // fix
{
    //ctor
}