C++多态性通过C回调丢失

Sil*_*pur 0 c c++ polymorphism callback

注意:为了清楚起见,在下面的代码片段中省略了constuctors/destructors和includes.

我正在使用一个函数registerCallback需要以下参数的库:

  • 一个C风格的函数指针,用于注册回调
  • 一个void*"用户-数据"传输任何一个认为合适的

因为我用C++编写代码而我希望我的回调函数调用一个类成员方法,由于registerCallback第一个参数的C样式,我不能直接做,我已经写了这个函数:

extern C {
    void handler( void* userData ) {
        (static_cast<Base*>(userData))->handle();
    }
}
Run Code Online (Sandbox Code Playgroud)

我使用的registerCallback功能如下:

class Base {
    public void handle() {}
};
...
Base b;
registerCallback( handler, &b );
Run Code Online (Sandbox Code Playgroud)

这到目前为止运作良好.

现在,让我们添加一些复杂性:

Baseclass有一个toto名为by 的纯虚函数handle(),我有Child1Child2扩展的类Base.

class Base {
    public:
        void handle() { toto(); }
        virtual void toto() = 0;
};
class Child1: public Base {
    public: virtual void toto() { cout << "CHILD 1" << endl; }
};
class Child2: public Base {
    public: virtual void toto() { cout << "CHILD 2" << endl; }
};
...
Child1 c;
registerCallback( handler, &c ); // --> seg fault!!
Run Code Online (Sandbox Code Playgroud)

这就是问题:因为在extern-C函数中,我userData转向Base*,对totoin 的调用handle()指的是一种假设Base::toto()方法,当触发回调时会导致seg错误.

如果另一方面我没有强制转换Base*,我得到‘void*’ is not a pointer-to-object type编译器错误.

我怎样才能保持变量的实际类型不被传递回调剥离?

编辑

这是来自GDB的堆栈跟踪:

Stacktrace:
#0  0x0000000000000000 in ?? ()
#1  0x00007ffff7bce41d in Base::handle ...
#2  0x00007ffff7bce110 in handler ...
Run Code Online (Sandbox Code Playgroud)

并备份在C handler函数中:

(gdb) p (static_cast<Base*>(userData))->handle
Cannot take address of method handle
Run Code Online (Sandbox Code Playgroud)

Bri*_*ian 6

因为在extern-C函数中,我userData转向Base*,对totoin 的调用handle()指的是一种假设Base::toto()方法

那应该不是问题.因为它toto是虚拟的,即使从非虚拟成员函数调用Base它,它也应该分配给对象的动态类型中的最终覆盖.

但是,您的代码无法保证在当前表单中工作,因为您在传递时Child1*直接转换为.这意味着该值将指向对象的第一个字节.当该指针转换为in时,结果值也将指向对象的第一个字节- 不一定指向对象子对象的第一个字节.void*&cregisterCallbackvoid*Child1Base*handlerChild1BaseChild1

为了确保您有后者,你需要转换&cBase* 之前它传递给registerCallback.这确保了指针值将被调整为指向Base*对象的子对象的第一个字节Child1.然后该指针将往返void*,一切都应该工作.

(除了评论中指出的内容之外 - 你可能忘了制作Child1Child2衍生出来Base.)