简体   繁体   中英

C++: location of definition/declaration of non-member function

I have a class Myclass:

in Myclass.h file:

class{
private:
    int sd;
    int sd2;

public:
    void func(int sd, short op, void *ptr);

    void start();
};

in Myclass.cpp file:

void Myclass::start(){
     struct arg_t *arg = (struct arg_t *)malloc(sizeof(struct arg_t));
     ....
     event_set(ev, sd, EV_READ, call_func, arg ); //this is a library API, which trigger the callback of call_func(sd, op, arg);
}

void Myclass::func(int sd, short op, void *ptr)){
...
if(some_conditions){
     struct arg_t *arg = (struct arg_t *)malloc(sizeof(struct arg_t))
     .... 
     event_set(ev, sd2, EV_READ, call_func, arg );
     .....

}
...
}

in main.cpp

int main(){
   Myclass obj;
   ....
   obj.start();
   ....
}

in start(), the event_set need a function of void(*func)() type as argument,but func() is of void Myclass::(*func)() type, so I define a new function something like below (the codes are not correct, but just show what I expect):

void call_func(int sd, short op, void *ptr){
    Myclass::func(int sd, short op, void *ptr);
}

however, I'm at a loss where to delcare and define call_func() so that the Myclass::start() can use call_func as argument and call_func() can call Myclass::func()

This is a known problem. Since pointers to class members are not regular pointers, one can not use class member functions in naive callbacks, which expect a simple function pointer.

A solution is to make a callback function static , often private , and call the corresponding class function using the callback argument. In your case, it would look like following:

class C {
private:
    int sd;
    static void call_func(int sd, short op, void* ptr) {
        C* obj = static_cast<C*>(ptr);
        obj->func(sd, op);
    }


public:
    void func(int sd, short op);

    void start()  {
        event_set(ev, sd, EV_READ, &call_func, this);
    }
};

EDIT

Fixed messed up start() and func() .

I'm at a loss where to delcare and define call_func() so that the Myclass::start() can use call_func as argument and call_func() can call Myclass::func()

You can put this all in your Myclass.cpp file, above the definition of Myclass::start().`

#include <Myclass.h>

void call_func(int sd, short op, void *ptr){
    Myclass::func(int sd, short op, void *ptr);
}

void Myclass::start(){
     event_set(ev, sd, EV_READ, call_func, NULL ); //this is a library API, which trigger the callback of call_func(sd, op, NULL);
}

void Myclass::func(int sd, short op, void *ptr)){
...
...
}

One other thing, with callback functions, the void* ptr is how you can pass a pointer to some data that the callback function will use. If you don't need anything like that then you don't need to be calling a non-static member function as the callback and you could simplify things. But to call non-static member function the way you're describing, you need an object to call it on, and that's what you would pass as the void *ptr :

// Myclass.h
class Myclass {
private:
    int sd;

public:
    void func(int sd, short op); // no void*
    void start();
};


// Myclass.cpp
#include <Myclass.h>

void call_func(int sd, short op, void *ptr){
    assert(ptr != NULL);
    static_cast<Myclass *>(ptr)->func(int sd, short op); // cast data to 'this' pointer
}

void Myclass::start(){
     event_set(ev, sd, EV_READ, call_func, this ); // pass the 'this' pointer as data
}

void Myclass::func(int sd, short op)){
...
...
}

the last argument of event_set() is still needed to be used for a pointer to an additional structure, so it can't be this

You need to pass this somehow or you can't call a member function, so if you have another structure you need to think about how to pass both.

Can the other structure or a pointer to it be a member of the object? If so, then do that and pass this as the void *ptr .

Another option is to define a struct just for passing the data through the callback:

struct callback_params {
  Myclass *c;
  other_struct *s;
};

But you have to create this callback_params struct somewhere where it will live long enough for the callback to be able to receive it, which can be tricky.

WRONG ANSWER!!!!

My old tablet didn't load the code sections of the question correctly and I miss important parts of the question...
Leaving here just as sake of completeness - maybe this can be util for someone else

SORRY

I don't know the complete stuff that you're doing but in this cases, if i don't need interface with old code I will go for std::function for sure.

But if is absolutely needed the pointers stuff, I generally do:

  • Put a very ugly name in the function - So every one will know that this is a 'hack' and not a good thing. ex: _func_call_wrapper_(...)
  • Put into the top of .cpp file the definition with the appropriated comments and so on. ex:

//This is a wrapper neeeded for... void __func_call_wrappper_(..);

  • Finally in the bottom of the .cpp file I define the function, of course, with a lot of comments of why this is needed.

Refs: ccpreference

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM