2014-11-12 4 views
5

Ich versuche, eine Klasse zu erstellen, um einige grundlegende Verhalten der libuv Netzwerkfunktionen zu abstrahieren.C++ - Fehler: Verweis auf nicht-statische Member-Funktion muss aufgerufen werden

#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); 
    } 
}; 

Das Problem mit dem Code, der zuvor gezeigt, dass, wenn ich versuche, es zu kompilieren wir die folgende Fehlermeldung erhalten:

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); 
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

Und es deutet auf listen_uv_listen_uv_connection_cb als die Schuldigen.

Kann mir jemand erklären, warum ist das ein Fehler, und wie soll ich es beheben?

Die uv_listen() und uv_connection_cb Unterschriften deklariert werden als

folgt
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

löschen behandelt Null-Zeiger von selbst, Ihre Überprüfung ist redundant – Slava

+0

@Slava Danke, wusste nicht darüber. – almosnow

+1

Können Sie bitte die aktuelle 'uv_listen()' Signatur anzeigen? –

Antwort

8

Sie können die nicht statische Elementfunktion nicht in einen Zeiger konvertieren, um mit derselben Signatur zu funktionieren, da die Memberfunktion über einen versteckten Parameter namens this verfügt. Einer der Lösung ist listen_uv_listen_uv_connection_cb statisch zu machen:

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 in der Lage sein eine nicht-statische Methode nennen Sie einen Weg brauchen würde einen Zeiger auf Ihre _tcp Instanz von „uv_stream_t * stream“ Parameter zu erhalten. Ich würde vorschlagen, „void * uv_handle_t.data“ Zeiger von diesem doc 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(); 
} 

Natürlich verwenden, sollten Sie this Zeiger auf uv_handle_t.data zuweisen, wenn Sie uv_tcp_t * initialisieren:

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 
    ... 
} 

und ich würde das Produkt bewegen Initialisierungscode für den Konstruktor.

Sie würden einen solchen statischen Wrapper für jeden Callback benötigen, den Sie mit dieser Bibliothek verwenden möchten. Mit C++ 11 können Sie wahrscheinlich stattdessen Lambda verwenden.

+0

Danke @slava. Kennen Sie eine Problemumgehung, um eine nicht statische Funktionsreferenz zu verwenden? Weil ich plane, auf viele Instanzvariablen innerhalb der 'listen_uv_listen_uv_connection_cb'-Funktion zuzugreifen. – almosnow

+0

Um mehr auszuarbeiten, enthält 'uv_tcp_t * tcp' einen Verweis auf die tatsächliche tcp-Verbindung. Wenn ich etwas mit dieser Verbindung in 'listen_uv_listen_uv_connection_cb' machen wollte (was ich definitiv tue), müsste ich' uv_tcp_t * tcp' auch statisch machen, und wenn ich 'tcp' statisch machen würde, wäre ich nicht in der Lage, neue zu erreichen Verbindungen durch mehr 'neue _tcp()' Instanzen. Das ist also das Problem. – almosnow

+0

@almosnow nein Sie müssen nicht 'uv_tcp_t * tcp' statisch machen, Sie erhalten es als erster Parameter im Callback. Siehe aktualisierte Antwort – Slava

0
void listen_uv_listen_uv_connection_cb(uv_stream_t* stream, int status) { 
     printf("NEW CONNECTION\n"); 
    };  <<<<<remove ; 

Es sollte am Ende der Funktionsdefinition kein Semikolon sein.

Und Sie sollten Konstruktor/Kopie ctr/assign-Operator für diese Klasse schreiben.

+0

würde ich sagen schreiben oder deaktivieren – Slava

+1

Danke für Ihre Beobachtung @ravi, Code funktioniert immer noch nicht. – almosnow

1

Der uv_listen() Rückruf-Connector erwartet eine static oder freie (außerhalb der Klasse) Funktion.

So sollten Sie Ihre Funktion erklären, wie diese

static void listen_uv_listen_uv_connection_cb(uv_stream_t* stream, int status) { 
    printf("NEW CONNECTION\n"); 
    _tcp* thisStream = static_cast<_tcp*>(stream); 
} 

Nun, die static_cast<> erfordert tatsächlich Ihre _tcp Klasse erbt von uv_stream_t

class _tcp : public uv_stream_t { 
    // ... 
}; 

auf your comment erweitern

"Could you please explain to me why does uv_listen expects a static function? Is this the behavior for all function pointer parameters?"

Es gibt einen Unterschied zwischen Klassenfunktionszeigern, die an eine Klasseninstanz zum Aufrufen gebunden sein müssen, und einfachen Funktionszeigern, die für jede Funktionsdefinition funktionieren.

Warum uv_listen() erwartet einen einfachen Funktionszeiger, ist schwer zu sagen. Vielleicht weil es eine native C-API ist (ich weiß es eigentlich nicht) oder wegen der Flexibilität.


HINWEIS: Sie sollten nicht führenden Unterstrichen für alle Symbole verwenden (wie in class _tcp)!

+0

zu verwenden Danke @ πάντα ῥεῖ, könnten Sie mir bitte erklären, warum uv_listen eine statische Funktion erwartet? Ist dies das Verhalten für alle Funktionszeigerparameter? – almosnow

Verwandte Themen