Fra*_*ank 3 c++ design-patterns callback
我尝试过各种各样的设计方法来解决这个问题,但我似乎无法做到这一点.
我需要公开一些静态函数来用作C lib的回调函数.但是,我希望实际的实现是非静态的,所以我可以使用虚函数并在基类中重用代码.如:
class Callbacks {
static void MyCallBack() { impl->MyCallBackImpl(); }
...
class CallbackImplBase {
virtual void MyCallBackImpl() = 0;
Run Code Online (Sandbox Code Playgroud)
但是我尝试解决这个问题(Singleton,让回调包含在实现者类中,等等).我最终陷入了死胡同(impl通常最终指向基类,而不是派生类).
我想知道它是否完全可能,或者我是否坚持创建某种辅助函数而不是使用继承?
虽然它可能看起来似乎适用于您的设置,但由于未定义C++ ABI,因此无法保证其正常工作.因此从技术上讲,您不能将C++静态成员函数用作C代码使用的函数指针.
所有C callacks(我知道)允许您将用户数据作为void*传回.您可以将其用作指向具有虚方法的对象的指针.但是,在将其转换为void*之前,必须确保将dynamic_cast <>()用于基类(具有回调中使用的虚方法的基类),否则可能无法正确解释另一端的指针(尤其是如果涉及多个继承).
例外:C不适用于异常(特别是带有回调的旧C库).所以不要指望逃避回调的异常为调用者提供任何有意义的东西(它们更可能导致应用程序终止).
你需要做的是使用extern"C"函数作为回调,它在知道类型的对象上调用虚方法并抛弃所有异常.
C pthread例程的示例
#include <iostream>
extern "C" void* start_thread(void* data);
class Work
{
public:
virtual ~Work() {}
virtual void doWork() = 0;
};
/*
* To be used as a callback for C code this MUST be declared as
* with extern "C" linkage to make sure the calling code can
* correctly call it
*/
void* start_thread(void* data)
{
/*
* Use reinterpret_cast<>() because the only thing you know
* that you can do is cast back to a Work* pointer.
*
*/
Work* work = reinterpret_cast<Work*>(data);
try
{
work->doWork();
}
catch(...)
{
// Never let an exception escape a callback.
// As you are being called back from C code this would probably result
// in program termination as the C ABI does not know how to cope with
// exceptions and thus would not be able to unwind the call stack.
//
// An exception is if the C code had been built with a C++ compiler
// But if like pthread this is an existing C lib you are unlikely to get
// the results you expect.
}
return NULL;
}
class PrintWork: public Work
{
public:
virtual void doWork()
{
std::cout << "Hi \n";
}
};
int main()
{
pthread_t thread;
PrintWork printer;
/*
* Use dynamic_cast<>() here because you must make sure that
* the underlying routine receives a Work* pointer
*
* As it is working with a void* there is no way for the compiler
* to do this intrinsically so you must do it manually at this end
*/
int check = pthread_create(&thread,NULL,start_thread,dynamic_cast<Work*>(&printer));
if (check == 0)
{
void* result;
pthread_join(thread,&result);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3026 次 |
| 最近记录: |