将函数从另一个类传递给另一个函数

  • 本文关键字:函数 另一个 c++
  • 更新时间 :
  • 英文 :


X11库中的XSetErrorHandler()函数需要一个函数。

如果我在main() [in main.cpp]上面定义一个函数,如:

int catch_error(Display *disp, XErrorEvent *xe){return 0;}

然后我做以下操作:

XSetErrorHandler(catch_error); 

如何将catch_error函数放在一个名为windowandler的类中,然后将其传递给XSetErrorHandler();

我试了如下:

WindowHandler window_handler = new WindowHandler();
XSetErrorHandler(WindowHandler::catch_error);
XSetErrorHandler(window_handler->catch_error);
XSetErrorHandler((*window_handler).catch_error);

1) int (WindowHandler::*)(Display *disp, xerrorvent *xe)"与&;xerrorhandler &;

类型的参数不兼容2)和3)指向绑定函数的指针只能用于调用该函数

谢谢你的帮助!

问题是非静态成员函数需要隐式的第一个参数,该参数是指向类(在本例中为WindowHandler)的指针或引用。因此,如果我们考虑隐式参数,则签名与自由catch_error函数不同。

我不知道XSetErrorHandler是如何声明的,但是该函数可能接受函子:在这种情况下,您可以将对WindowHandler::catch_error的调用包装在一个lambda表达式中,该表达式捕获指向WindowHandler实例的指针。

WindowHandler* window_handler = new WindowHandler();
XSetErrorHandler(
[window_handler](Display *disp, XErrorEvent *xe) {
return window_handler->catch_error(disp, xe);
}
);
delete window_handler; // if you really must use new (why would you ever?), please also delete.

下面是一些关于成员函数指针的进一步阅读:https://isocpp.org/wiki/faq/pointers-to-members

<标题>

编辑:我刚刚意识到,XSetErrorHandler接受函函数,但只接受函数指针https://tronche.com/gui/x/xlib/event-handling/protocol-errors/XSetErrorHandler.html。在本例中,WindowHandler::catch_error必须是静态的。如果lambda没有捕获任何内容,则只能将其视为函数指针。

如果您真的想捕获WindowHandler成员中的error_flag,我认为您唯一的选择是拥有WindowHandler的一个全局实例(所谓的单例)。然后,静态catch_error函数可以设置这个单例的成员,不需要隐式this参数。

注意全局变量和单例是不鼓励使用的,如果可能的话应该避免使用。在某些情况下,这是不可能的。日志记录和错误处理经常出现在这些场景中。

#include <iostream>
#include <memory>
struct Display {};
struct XErrorEvent {};
void XSetErrorHandler(
int (*handler)(Display *, XErrorEvent *)
) {}
class WindowHandler 
{
private:
// constructor is private: No other class should be allowed to construct instances
WindowHandler() = default;
int catch_error_impl(Display*, XErrorEvent*) {
std::cout << "Error happenedn";
error_flag = 1;
return 0;
}  
public:
// don't copy or move a singleton
WindowHandler(WindowHandler const&) = delete;
WindowHandler(WindowHandler&&) = delete;
// the global WindowHandler singleton gets instantiated the first time the get_instance_ptr function is called
static WindowHandler* get_instance_ptr() {
// calling new in the argument of unique_ptr ctor is ok. memory is freed when the dtor is called
static auto handler = std::unique_ptr<WindowHandler>(new WindowHandler());
return handler.get();
}
static int catch_error(Display* disp, XErrorEvent* xe) {
return get_instance_ptr()->catch_error_impl(disp, xe);
} 
int error_flag {0};
};
int main()
{
XSetErrorHandler(WindowHandler::catch_error);
std::cout << WindowHandler::get_instance_ptr()->error_flag << std::endl;
}

https://godbolt.org/z/MTWcfK3bs

最新更新