从c代码中的c++库导出观察者模式

Export observer pattern from a c++ library in c code

本文关键字:观察者模式 c++ 代码      更新时间:2023-10-16

我有一个c++共享库,可以生成一些事件。我有一个侦听器的接口和一个能够注册观察者和激发事件的类。

这个库可以从java、C#和C++代码(使用不同的编译器编译)中使用,所以我有两个文件头:*.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 );

并以某种方式将CCD_ 1与CCD_

// 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 ); 
    // ...
}

这种方法对我来说不太好。有更好的方法吗?

您缺少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);
    ...