将成员函数作为参数传递给构造函数

4
我有一个按钮类。我希望按钮类的构造函数能够接受按下按钮时调用的函数。如果按钮类只从一个类中获取函数,那么这很容易实现。但是,按钮的构造函数接受函数的目的是,无论在哪个类中创建按钮,它都将能够存储指向所在类中函数的指针。
举例说明:
struct Button {
    Button(void (*functionPtr)()) {
        // Store the function pointer to be called later
    }
};

struct SomeClass {
    void LoadFile();

    SomeClass() {
        Button* temp1 = new Button(&LoadFile); // ???
    }
};

struct AnotherClass {
    void SaveFile();

    SomeClass() {
        Button* temp2 = new Button(&SaveFile); // ???
    }
};

我该如何使这个工作起来?


2
如何存储一个 std::function<void()> 成员,然后传递 lambda 表达式来为您进行类捕获? - Baum mit Augen
希望你意识到无论如何都需要一个this指针,无论是将其隐藏在绑定包装器中还是在函数指针中提供(目前甚至不是成员函数指针)。我建议首先解决这个问题。 - WhozCraig
你可能想要查看 boost::signals,不过正如 @BaummitAugen 所指出的那样,现在使用 std::function + lambda 表达式也是很好的选择。 - Ami Tavory
树上长眼睛,我该怎么做?我完全忘记了Lambda是什么以及它们如何工作。 - GravenFear
2个回答

4
指向函数的指针和指向成员函数的指针,尽管看起来很相似,但实际上完全不同。 void (*functionPtr)()是一个指向不带参数并返回void的函数的指针。&AnotherClass::SaveFile是指向AnotherClass成员函数的指针...它的类型是void (AnotherClass::*)()。请注意,类名是类型的一部分,因此您不能简单地存储任意类的指向成员函数的指针。此外,要调用指向成员函数的指针,您需要一个实例指针——您必须以某种方式存储它,但这些也会有不同的类型!
在C++11中,您可以使用类型擦除来代替。
std::function<void()> callback;

并将任意可调用对象分配给它:

template <typename F>
Button(F cb) 
: callback(cb)
{ }

接下来,您可以使用std::bind创建一个按钮:

Button* temp1 = new Button(std::bind(&OtherClass::LoadFile, this));
Button* temp2 = new Button(std::bind(&AnotherClass::SaveFile, this));

现在,temp1->callback() 将实际调用其构造时传入的 OtherClass 实例上的 LoadFile() 方法。这正是您想要的。而且,我们仍然可以使用自由函数。
void whatever();
Button* temp3 = new Button(whatever);

请注意使用原始指针和 new,并优先考虑使用 unique_ptr


我在其他地方看到过类似的东西,但我仍然不理解。回调是button.h中的成员变量吗?当您创建temp1时,究竟发生了什么? - GravenFear
@GravenFear 是的,这里是关于std::function的文档。 - Barry
当我使用不带“&”的绑定时,它会抱怨我传递的函数缺少参数列表,但是当我添加“&”时,输出窗口中会给出一个5行的“未解决的外部符号”链接器错误(我正在使用Visual Studio)。有什么建议吗? - GravenFear
@GravenFear,你需要使用 & 符号,而且你的函数未定义。 - Barry
感谢你的帮助,Barry。我已经解决了问题!!!链接器错误不是由于未定义函数引起的,而是因为我无意中在.h和.cpp文件中定义了模板。这是新手犯的错误,真是太傻了。再次感谢,我已经花了很长时间来让这个类正常工作。 - GravenFear
在展示成员函数指针和普通指针的不同之处时,+1。人们可能也会发现这个SO问题和答案有帮助:C ++对象保留模板函数和参数作为成员以稍后调用 - BoltzmannBrain

0

你不能真正拥有一个成员函数的指针,因为没有隐藏的this指针,对象无法被调用。

有几种常见的解决方案可以解决你试图解决的问题。

C方式:

除了函数指针之外,还要存储一个void*。然后将void*传递给回调函数。这种方法不太“安全”,但在C中很常见。

OOP方式#1:

子类化Button并在基类上有一个虚函数,比如onPress,可以在子类中实现。

OOP方式#2:

有一个独立于Button的回调接口,你的自定义类实现它。

编辑:或者像评论中提到的那样使用lambda表达式。我自己仍在重新学习现代C++。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接