我试图创建一个类来抽象libuv网络功能的一些基本行为。
#define TCP_BACKLOG 256
class _tcp {
uv_tcp_t* tcp = NULL;
public:
~_tcp() { delete tcp; }
void listen_uv_listen_uv_connection_cb(uv_stream_t* stream, int status) {
printf("NEW CONNECTION\n");
}
void listen(const char* host, int port) {
tcp = new uv_tcp_t();
uv_tcp_init(uv_default_loop(), tcp);
sockaddr_in* addr = new sockaddr_in();
uv_ip4_addr(host, port, addr);
uv_tcp_bind(tcp, (const sockaddr*)addr, 0);
delete addr;
uv_listen((uv_stream_t*)tcp, TCP_BACKLOG, listen_uv_listen_uv_connection_cb);
}
};
以前显示的代码的问题是,当我尝试编译它时,我收到以下错误:
error: reference to non-static member function must be called
on: uv_listen((uv_stream_t*)tcp, TCP_BACKLOG, listen_uv_listen_uv_connection_cb);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
它指出listen_uv_listen_uv_connection_cb
是罪魁祸首。
有人可以向我解释,为什么这是一个错误,我该如何解决?
uv_listen()
和uv_connection_cb
签名声明如下
UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);
typedef void (*uv_connection_cb)(uv_stream_t* server, int status);
答案 0 :(得分:8)
即使使用相同的签名,也无法将非静态成员函数转换为指向函数的指针,因为技术上成员函数具有名为this
的隐藏参数。其中一个解决方案是使listen_uv_listen_uv_connection_cb
静态:
class _tcp {
uv_tcp_t* tcp = NULL;
public:
~_tcp() { delete tcp; }
static void listen_uv_listen_uv_connection_cb(uv_stream_t* stream, int status) {
printf("NEW CONNECTION\n");
}
void listen(const char* host, int port) {
tcp = new uv_tcp_t();
uv_tcp_init(uv_default_loop(), tcp);
sockaddr_in* addr = new sockaddr_in();
uv_ip4_addr(host, port, addr);
uv_tcp_bind(tcp, (const sockaddr*)addr, 0);
delete addr;
uv_listen((uv_stream_t*)tcp, TCP_BACKLOG,
&_tcp::listen_uv_listen_uv_connection_cb);
}
};
PS能够调用非静态方法,您需要一种从“uv_stream_t * stream”参数获取指向_tcp
实例的指针的方法。我建议使用此文档中的“void * uv_handle_t.data”指针http://docs.libuv.org/en/latest/handle.html#c.uv_handle_t
static void listen_uv_listen_uv_connection_cb(uv_stream_t* stream, int status) {
_tcp *tcp = static_cast<_tcp *>( stream->data );
tcp->regularMethod();
}
当您初始化this
时,您应该将uv_handle_t.data
指针指向uv_tcp_t *
:
void listen(const char* host, int port) {
tcp = new uv_tcp_t();
uv_tcp_init(uv_default_loop(), tcp);
tcp->data = this; // do not forget it
...
}
我会将此初始化代码移动到构造函数。
对于要与此库一起使用的每个回调,您都需要这样的静态包装器。使用c ++ 11,您可能可以使用lambda。
答案 1 :(得分:1)
uv_listen()
回调连接器需要static
或免费(外部类)功能。
因此你应该声明你的功能
static void listen_uv_listen_uv_connection_cb(uv_stream_t* stream, int status) {
printf("NEW CONNECTION\n");
_tcp* thisStream = static_cast<_tcp*>(stream);
}
嗯,static_cast<>
实际上要求您的_tcp
类继承自uv_stream_t
class _tcp : public uv_stream_t {
// ...
};
“你能否向我解释为什么uv_listen需要一个静态函数?这是所有函数指针参数的行为吗?”
类成员函数指针之间存在差异,需要绑定到用于调用的类实例,以及普通函数指针,它们适用于任何函数定义。
为什么uv_listen()
期望一个普通的函数指针,很难说。可能是因为它是一个原生的C-API(我实际上不知道它),或者为了灵活性。
注意:您不应对任何符号使用前导下划线(如class _tcp
中所示)!
答案 2 :(得分:0)
void listen_uv_listen_uv_connection_cb(uv_stream_t* stream, int status) {
printf("NEW CONNECTION\n");
}; <<<<<remove ;
在函数定义的末尾不应该有分号。
你应该为这个类编写构造函数/ copy ctr / assign运算符。