C ++错误:必须调用对非静态成员函数的引用

时间:2014-11-12 18:35:39

标签: c++ libuv

我试图创建一个类来抽象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);

3 个答案:

答案 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 {
    // ...
};

延长your comment

  

“你能否向我解释为什么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运算符。