JosiP
JosiP

Reputation: 3079

C++ virtual method pointer

Im writing a simple socket server in C++. I've already have some libs from C which fires callback when event read happens on socket. I want client who will use that class will impement its own mechanims to handle those events. My base class is:

class CBaseServer{
    ...
    void monitorDataArrived(int fd);
    virtual void monitorOnDataArrived(void *context, int fd) = 0;
}

in this class pointer to monitorOnDataArrived(void *context, int fd) has to be passed to extarnal C function called AddClient(int mask, proc, fd) whenever new socket will appear. proc is defined as:

typedef void(*proc)(void *context, int fd)
CBaseServer::monitorDataArrived(fd){
     proc p = (void (*)(void*, int)&CBase::monitorOnDataArrived; 
     addClient(MASK_READ, p, fd);
}

now client is doing:

class Reader : class CBase{
    void monitorOnDataArrived(void *context, int fd) {
        std::cout << "hey, data arrived"
    }
}

My question is: im having compliation errors: undefined refernece to CBaseServer::monitorOnDataArrived(void *, int)

Is there any way to fix it ?

regards J.

Upvotes: 0

Views: 278

Answers (1)

LoPiTaL
LoPiTaL

Reputation: 2595

You are misunderstanding the function pointers in C++.

You cannot pass a member function to a C handler, since a member function has an additional implicit parameter (the "this" parameter).

What is the solution? The solution is to use static functions which will cast the void * context parameter into an instance of your base class, and then calling the virtual function:

class CBaseServer{
    ...
    //Watch that the context parameter has been moved from the virtual to the other
    //function, which is now also static.
    static void monitorDataArrived(void *context, int fd);
    virtual void monitorOnDataArrived(int fd) = 0;
}

The dispatching code would be as following:

void CBaseServer::monitorDataArrived(void *context, int fd){
    CBaseServer * server=(CBaseServer*)context;
    server->monitorOnDataArrived(fd);
}

And the registration code would be:

class Reader : class CBase{
    void monitorOnDataArrived(int fd) {
        std::cout << "hey, data arrived"
    }
}
....
Reader * theReader=new Reader();

//The instance theReader of type Reader must be passed to the registration function
//as the void * context parameter.
addClient(MASK_READ, &theReader);  

Upvotes: 3

Related Questions