我有一个c ++共享库,可以生成一些事件。我有一个监听器的接口和一个能够注册观察者和激活事件的类。
这个库可以用于java,C#和C ++代码(用differenc编译器编译),所以我有两个文件头:* .h用于ANSI C接口,* .hpp用于直接从C ++代码使用库。现在我无法想象导出观察者模式如何使用类似C的接口。
以下是代码结构的一小部分。
// hpp file
class IListener
{
public:
virtual ~IListener() {}
virtual void event1( int ) = 0;
virtual void event2() = 0;
};
using IListenerPtr = std::shared_ptr< IListener >;
class Controller
{
public:
Controller( IListenerPtr listener );
void addListener( IListenerPtr listener );
private:
void threadFunc()
{
while ( true )
{
// an event occured
for ( auto& e : mListeners )
e->event1( 2 );
for ( auto& e : mListeners )
e->event2();
}
}
private:
std::vector< IListenerPtr > mListeners;
};
// h file
#if defined( __MSCVER ) || defined( __MINGW32__ ) || defined( __MINGW64__ )
# define LIB_CALLBACK __stdcall
# define LIB_CALL __cdecl
# if defined( AAMS_EXPORTS )
# define LIB_API __declspec( dllexport )
# else
# define LIB_API __declspec( dllimport )
# endif
#else
# define LIB_API
#endif // WIN32
typedef int libError;
LIB_API libError LIB_CALL libInit( ???? );
如何从C代码中使用此库?第一次尝试可能是:
typedef struct libListenerTag
{
typedef void (LIB_CALLBACK *Event1Func)( int );
typedef void (LIB_CALLBACK *Event2Func)();
Event1Func Event1;
Event2Func Event2;
} libListener;
LIB_API libError LIB_CALL libInit( libListener* listener );
并以某种方式将libListener
绑定到IListener
// cpp file
class CListener : public IListener
{
public:
CListener( libListener* listener
: mListener( listener )
{
}
void event1( int i ) { mListener->Event1( i ); }
void event2() { mListener->Event12(); }
private:
libListener* mListener;
}
Controller* g_controller = nullptr;
LIB_API libError LIB_CALL libInit( libListener* listener )
{
g_controller = new Controller( make_shared< CListener >( listener );
// ...
}
这种方法对我来说看起来不太好。是一种更好的方法来实现这一目标吗?
答案 0 :(得分:1)
你错过了C事件回调中标准的东西:一个上下文指针。
在C ++中,您的IListener
子类在其回调中获得一个隐式this
指针,这意味着它可以在实例中存储状态和上下文信息。
对于自由函数,你没有这个,所以你需要添加一个显式参数。
/* c_interface.h */
typedef void (*EventCallback1)(void *context, int arg);
typedef void (*EventCallback2)(void *context);
struct Listener; /* opaque type */
struct Listener *create_listener(EventCallback1, EventCallback2, void *context);
void destroy_listener(struct Listener*);
所以从C方面,你将所需的任何状态打包到一个结构中,将它作为你的上下文传递给create_listener
,并在它们被调用时将它传递给你的函数。
// c_implementation.cpp
extern "C" {
#include "c_interface.h"
struct Listener: public IListener {
EventCallback1 cb1;
EventCallback2 cb2;
void *context;
Listener(EventCallback1 e1, EventCallback2 e2, void *c)
: cb1(e1), cb2(e2), context(c)
{}
virtual void event1(int arg) {
(*cb1)(context, arg);
}
virtual void event2() {
(*cb2)(context);
}
};
Listener *create_listener(EventCallback1 cb1, EventCallback2 cb2, void *context) {
return new Listener(cb1, cb2, context);
}
}
客户端代码类似于
#include "c_interface.h"
struct MyContext {
int things;
double needed;
int to_handle;
char callbacks[42];
};
void cb0(void *context) {}
void cb1(void *context, int arg) {
struct MyContext *c = (struct MyContext *)context;
c->things = arg;
}
void foo() {
struct MyContext *context = malloc(sizeof(*context));
struct Listener *l = create_listener(cb1, cb0, context);
...