简体   繁体   中英

using c++ class member function with C function pointer

I am using a C library that implements a command shell. Custom shell commands are registered by implementing a function with the following call signature:

typedef void(* shellcmd_t)(BaseSequentialStream *chp, int argc, char *argv[])

And then registering that function in a static structure which maps a string command name to that function pointer as follows:

static const ShellCommand commands[] = {
  {"myfunction", myfunction},
  {NULL, NULL}
}

Where myfunction looks like:

void myfunction(BaseSequentialStream *chp, int argc, char *argv[])
{
   // do some stuff
}

I am using C++ and would like to implement some shell commands as class instance member functions (not static member functions). Is there a way to use anything in <functional> so that I can get a compatible function pointer from a class instance member function and register it with the array of ShellCommand structs? I've been reading about std::bind and std::function and am sort of getting the impression you can give them a pointer to a C-style function, but you can't get a pointer to a C-style function from them so it doesn't seem like it will work, but maybe I'm just missing something.

If anybody has a good approach to solving this problem, I would love to hear about it. It seems like I might have to implement it as a flat C-function that can then call something that will give it a pointer/reference to the instance I want and then once I have that I can forward the call to that instances member function. It just seems kind of messy and was hoping there was a better way.

No this can't be directly the way that you'd like it to. In a C interface you have no way to pass the implicit instance of the class somehow, a C interface simply doesn't have a slot for that. So you would have to pass the pointer to the instance in explicitly and call the class function. The gain that this would bring you is proctection of the other class methods.

All of this has nothing to do with the name mangling aspect of extern "C" linkage, but eventually with the ABI. Once you export a pointer to function from a compilation unit in a variable (here the array elements), it doesn't matter if the "orginal" symbol had been mangled or not. The type system guarantees that the function will always be called with the correct calling convention.

Since you are using a C library, you should pass extern "C" functions to the C library. This is to make sure that you pass to the C library a function that is compatible to the C ABI (this is important on systems where the C ABI and the C++ ABI differ). Since the API looks very regular, you can use a macro to make this easier in the C++ code:

#define DEFINE_SHELL_COMMAND(cmd) \
    extern "C" void cmd##_c_wrap (BaseSequentialStream *chp, int argc, char *argv[]) { \
        cmd().execute(chp, argc, argv); \
    } \
    ShellCommand cmd##Entry = { #cmd, cmd##_c_wrap }

class ShellCommandClass {
protected:
    virtual ~ShellCommandClass () {}
public:
    virtual void execute (BaseSequentialStream *chp, int argc, char *argv[]) = 0;
};

class myfunctionClass : public ShellCommandClass {
    //...
public:
    void execute (BaseSequentialStream *chp, int argc, char *argv[]) { /* ... */ }
};

ShellCommandClass & myfunction () {
    static myfunctionClass cmd;
    return cmd;
}

DEFINE_SHELL_COMMAND(myfunction);

static const ShellCommand commands[] = {
    myfunctionEntry,
    {NULL, NULL}
}

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