我有一个类stickyNotes
,其中有一个函数addNote
,它是一个公共的非静态函数。
在代码中,定义了一个新类型:
typedef void(*fptr)
我还有一个类Button
,该类在其构造函数中使用类型为fptr
的变量,我有一个函数makeButton()
返回一个Button
对象。
stickyNotes
还有一个名为rendermainWindow
的成员,它呈现主窗口并添加一个按钮,我试图创建一个类型为fptr
的新变量,该变量设置为以下地址stickyNotes::addNote
,但出现错误:
'&':对绑定成员函数表达式的非法操作
stickyNotes::rendermainWindow
:
void stickyNotes::rendermainWindow() {
/*
Renders the main window
*/
this->buttonList.empty(); // buttonList is a list of all buttons
mainWindow->clear(sf::Color(29, 29, 27, 255)); // clearing the window
sf::Vector2u windowDimensions = mainWindow->getSize(); // getting window dimensions
fptr cb = &this->addNote; <-------- ERROR HERE
Button plusB = makeButton((int)(windowDimensions.x * 0.75),
(int)(windowDimensions.y * 0.15),
(int)(windowDimensions.x * 0.85),
(int)(windowDimensions.y * 0.25),
mainWindow,
cb);
// first button to add stuff
std::vector<Button> vect;
vect.push_back(plusB);
this->buttonList.push_back(vect);
renderNotes();
}
用this->addNote
代替stickyNotes::addNote
。
我不想使addNote成为静态。并且我想使其保持公开状态,如何使用addNote的回调函数创建按钮? 如果有解决方法,我会很高兴听到它。
答案 0 :(得分:1)
成员函数只是类命名空间中的偏移量,因此您不能将偏移量用作绝对地址。
简便的方法是创建一个接口,在您的类中实现它,然后返回或分配this
作为接口。
其他选项是创建指向成员函数的指针。
例如:void (Class::*pfunc)()
将声明pfunc
指针,该指针可以指向class Class
的成员函数,例如void Class::Member()
如@GoswinvonBrederlow在评论中所建议,请使用lambda并将其返回或分配为std::function
:
std::function<void ()> Class::f()
{
return []() { /* do something...*/ };
}
答案 1 :(得分:1)
您正在尝试将回调传递给按钮。如果您要求回调函数是一个简单的函数指针(不接收任何参数),则您的回调函数将无法保留任何 state 。
但是,所有非静态成员函数都需要至少一个状态才能被调用:它们需要知道要使用/处理哪个对象。
这两个在本质上是矛盾的:如果您的按钮带有简单的函数指针,则不能将其用于调用成员函数(不包括诸如全局状态之类的可怕骇客)。
解决此问题的一种方法是使用成员函数指针:这些指针指定它们在哪个类上操作(即是其成员函数),并且必须在该类的实例上调用。由于您可能希望按钮回调可用于多个类,因此可以使用多态-这是SHR建议的接口解决方案。
按钮界面的另一个选项是获取(并存储)std::function<void()>
而不是函数指针。 std::function
可以存储状态,并且可以很方便地与lambda函数一起使用:
Button plusB = makeButton(/* ... */, [this]() { addNote(); });
最后,您可以允许用户将一些“自定义数据”传递给按钮界面,可能以void*
或std::any
的形式传递给回调。然后用户可以存储例如该自定义数据中的stickyNotes
实例。这与简单的函数指针兼容。但是,此方法绕过了类型安全性,并且级别很低。它在某些库中使用,因为它很通用,但是比起std::function
方法来说,它更令人讨厌。