c++ - 具有函数指针的类,可以在不同实例中调用多种函数

标签 c++ class function pointers

我正在用 SDL 编写类似于按钮的东西,如果我与之交互,它可以执行某些操作。我想将每个按钮存储在一个容器中(在列表或双端队列之类的东西中),这样我就可以调用它们自己的绘图函数,而且我还可以检查我点击了哪个按钮。所以,我认为最简单的方法是从通用类(“Button”)实例化它们,这样它们都有位置、颜色等,还有一个函数指针,我可以在实例化它们时将其设置为自定义函数.

我的问题是,当我在类中定义函数指针时,我必须声明一个参数列表,但有时我需要一个不同的参数列表(例如:

MyButton button() 
button.fooptr=quit; //quit is a void function with no arguments
button.fooptr();
//another case
button.fooptr=print; //print is a void function which takes an SDL_Surface* as an argument.
button.fooptr(screen);

我已经尝试将函数指针定义为 void (*fooptr)(...),如果我的函数有 (...) 作为参数,它会很好地工作,但是如果我尝试使用 fooptr(screen) 调用该函数,该函数看不到我传递给它的屏幕变量。是否有任何解决方案能够将自定义数量的参数传递给特定函数,并将零参数传递给没有参数的函数?

最佳答案

您描述的定义和调用函数的方式不是很安全。这是因为正如 Oli 在他们的评论中指出的那样,很容易错误地调用该函数。如果目标函数需要 3 个参数,而你最终只传递了 1 个,你就会得到未定义的行为,任何事情都有可能发生。在这种情况下,“任何事情”都将变得很糟糕。

如果您提前知道参数,您可以使用 std::function , std::bind以及早期绑定(bind)参数以更安全的方式调用函数。这将允许您在您[应该]知道需要传递哪些参数、绑定(bind)参数然后设置fooptr 的位置创建一个函数对象。

下面的示例使用您问题中的代码,并使用 std::bindstd::function 对其进行扩展,以安全统一的方式调用函数。它还包括使用 std::reference_wrapper 的示例允许通过引用传递参数。

#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <functional>

struct SDLSurface 
{
    std::string str;
};

struct Button
{
    std::function<void(void)> fooptr;
};

void quit()
{
    std::cout << "called quit()" << std::endl;
}

void print(SDLSurface *surface)
{
    std::cout << "called print(\"" << surface->str << "\")" << std::endl;
}

void print_string(const std::string& str)
{
    std::cout << "called print_string(\"" << str << "\")" << std::endl;
}


int main()
{
    std::vector<std::unique_ptr<Button>> buttons;
    std::unique_ptr<Button> b;

    // Create a button and assign a function that takes no parameters
    b.reset(new Button());
    b->fooptr = quit;
    buttons.push_back(std::move(b));

    // Create a button and assign a function
    b.reset(new Button());
    SDLSurface  surface;
    b->fooptr = std::bind(print, &surface);
    buttons.push_back(std::move(b));

    // Create a button and assign a function taking a parameter by reference
    b.reset(new Button());
    std::string string_param;
    // Since we are passing by reference and want to bind to an existing variable
    // we need to use a reference wrapper.
    b->fooptr = std::bind(
        print_string,
        std::reference_wrapper<const std::string>(string_param));
    buttons.push_back(std::move(b));

    // Call all functions setting the value of string_param before we do.
    surface.str = "hello";
    string_param = "world";
    for(auto it = buttons.begin(); it != buttons.end(); ++it)
    {
        (*it)->fooptr();
    }
}

关于c++ - 具有函数指针的类,可以在不同实例中调用多种函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17277690/

相关文章:

java - 无法从JAVA中同一类的另一个方法调用方法

php - 匿名类构造

excel - VBA 对象数据在集合中被覆盖

c - 在 C 中将指针传递给只读函数

c++ - 为 QAudioDecoder 子类化 QIODevice

c++ - 如何解释 Variadic 模板中的继承?

c++ - C 或 C++ 和 Linux 中的屏幕捕获程序

Javascript 函数调用具有不同的调用方式

Python 装饰器? - 有人可以解释一下吗?

c++ - sprintf函数的问题,last参数写错了