Sil*_*pur 0 c c++ polymorphism callback
注意:为了清楚起见,在下面的代码片段中省略了constuctors/destructors和includes.
我正在使用一个函数registerCallback需要以下参数的库:
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(),我有Child1和Child2扩展的类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)
因为在extern-C函数中,我
userData转向Base*,对totoin 的调用handle()指的是一种假设Base::toto()方法
那应该不是问题.因为它toto是虚拟的,即使从非虚拟成员函数调用Base它,它也应该分配给对象的动态类型中的最终覆盖.
但是,您的代码无法保证在当前表单中工作,因为您在传递时Child1*直接转换为.这意味着该值将指向对象的第一个字节.当该指针转换为in时,结果值也将指向对象的第一个字节- 不一定指向对象子对象的第一个字节.void*&cregisterCallbackvoid*Child1Base*handlerChild1BaseChild1
为了确保您有后者,你需要转换&c到Base* 之前它传递给registerCallback.这确保了指针值将被调整为指向Base*对象的子对象的第一个字节Child1.然后该指针将往返void*,一切都应该工作.
(除了评论中指出的内容之外 - 你可能忘了制作Child1和Child2衍生出来Base.)
| 归档时间: |
|
| 查看次数: |
149 次 |
| 最近记录: |