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

时间:2013-07-30 13:10:12

标签: c++ c observer-pattern

我有一个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 ); 

    // ...
}

这种方法对我来说看起来不太好。是一种更好的方法来实现这一目标吗?

1 个答案:

答案 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);
    ...