简体   繁体   English

使用C ++类成员函数和C函数指针

[英]using c++ class member function with C function pointer

I am using a C library that implements a command shell. 我正在使用实现命令外壳程序的C库。 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: myfunction如下所示:

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). 我正在使用C ++,并希望将一些Shell命令作为类实例成员函数(而非静态成员函数)实现。 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? 有没有一种方法可以在<functional>使用任何东西,以便可以从类实例成员函数中获取兼容的函数指针,并将其注册到ShellCommand结构数组中? 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. 我一直在阅读有关std :: bind和std :: function的内容,并且给人一种印象,您可以给他们一个指向C样式函数的指针,但是您不能从中获取指向C样式函数的指针他们似乎无法正常工作,但也许我只是缺少一些东西。

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. 似乎我可能必须将其实现为平面C函数,然后才能调用某些函数,该函数将为它提供指向想要的实例的指针/引用,然后一旦获得,便可以将调用转发给该实例成员函数。 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. 在C接口中,您无法以某种方式传递类的隐式实例,C接口根本没有用于此的插槽。 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. 所有这些都与extern "C"链接的名称修改方面无关,但最终与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. 由于您使用的是C库,因此应将extern "C"函数传递给C库。 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). 这是为了确保您将与C ABI兼容的函数传递给C库(这在C ABI和C ++ ABI不同的系统上很重要)。 Since the API looks very regular, you can use a macro to make this easier in the C++ code: 由于API看起来很常规,因此您可以使用宏在C ++代码中简化此操作:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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