0

我正在寻找一种方法来避免以下问题中的系统动态转换。

我有 Action 对象和 Message 对象。Action 对象具有发出消息的方法和其他接受消息的方法。当然还有派生的 Action 类和 Messages 类。对象及其方法在运行时通过基于定义互连对象网络的配置文件的字符串标识来动态连接。

这相当于一个信号槽系统,它对参数的数量和类型有很强的约束。所有信号都发出从 Message 类派生的消息,所有插槽都接受从 Message 类派生的消息。

连接为 NxN。因此信号是多播的,插槽可以接受来自多个来源的信号。

当前的实现是使用 Link 类来实例化信号和插槽之间的连接。信号和槽是函子成员变量。每个 Action 对象都有两个映射。一个从字符串名称到信号,一个从字符串名称到插槽。还有一个动作名称到实例的全局映射。跟踪目标操作(槽)中的链接的好处是在实例被销毁时正确断开所有链接。

在第一遍中,配置文件中定义的所有动作实例都被实例化,在第二遍中,链接被实例化,将信号连接到插槽。

问题是您将如何实现这一点,以便仅在实例化链接时执行消息类型匹配检查,并且仅在需要时执行动态转换。

例如,如果我们有消息基类 M 和 M 的子类 M1 和 M1 的子类 M2,则从 signal(M2) 到 slot(M1) 或 slot(M) 的链接不会执行动态转换,并且链接从信号(M1)或信号(M)到槽(M2)将执行动态转换。只有动态转换成功时才调用 slot 方法(不返回 nullptr)。

在每次调用时执行动态转换的实现是微不足道的。如果可能,我会寻求解决方案来避免这种情况。

我目前的理解是,由于动态绑定,我不能使用 boost::signals。

4

1 回答 1

0

我已经解决了我的问题。这是非常简洁的代码。信号也是一个模板类,它简单地定义了它可能发出的消息类型。因此,在将信号与槽连接时,Link 构造函数可以检查信号发出的消息类型与槽接受的消息类型的多态兼容性。然后无论是否需要动态转换,它都会复制适当的函数指针。此处未显示的是 Type 类以及如何使用它来检查消息类型的兼容性。

答案是如何定义这两个槽函数及其函数指针。

这是一个如何在类中定义插槽的示例:

class MyAction : public Action
{
public:
    //! Define shared pointer on object
    typedef std::shared_ptr<MyAction> Ptr;

    //! Constructor
    MyAction( const std::string& name )
        : Action(name),
          m_slotMsgM( this ),
          m_slotMsgA( this ),
          m_slotMsgB( this )
    {
    }

    //! Register the slots with their name for dynamic linking
    void configure()
    {
        add("processMsgM", &m_slotMsgM );
        add("processMsgA", &m_slotMsgA );
        add("processMsgB", &m_slotMsgB );
    }

    //! Slot method 
    void processMsgM( Message::Ptr msg, Link * link = nullptr )
    {
        cout << "MyAction::processMsgM: Msg " << msg->type().name() << endl;
    }

    //! Slot method 
    void processMsgA( MsgA::Ptr msg, Link * link = nullptr )
    {
        cout << "MyAction::processMsgA: Msg " << msg->type().name() << endl;
    }

    //! Slot method 
    void processMsgB( MsgB::Ptr msg, Link * link = nullptr )
    {
        cout << "MyAction::processMsgB: Msg " << msg->type().name() << endl;
    }

protected:
    //! Define slots
    SlotT<MyAction, Message, &MyAction::processMsgM> m_slotMsgM;
    SlotT<MyAction, MsgA, &MyAction::processMsgA> m_slotMsgA;
    SlotT<MyAction, MsgB, &MyAction::processMsgB> m_slotMsgB;
};

这是 Slot 和 SlotT 类的定义。

class Link;
typedef std::set<Link*> LinkSet;

//! Base class for Slot template class
class Slot
{
    friend class Link;
public:
    //! Slot function pointer
    typedef std::function<void ( Message::Ptr, Link* )> Function;

    //! Disconnect all links
    ~Slot();

    //! Return the type of message accepted by this Slot function
    const TypeDef& messageType() const { return m_msgType; }

    //! Return slot function applying a dynamic cast on the message pointer
    Function getDynamicCastFunction() const
        { return m_dynamicCastFunction; }

    //! Return slot function applying a static cast on the message pointer
    Function getStaticCastFunction() const
        { return m_staticCastFunction; }

    //! Operator () using the dynamic cast
    void operator()(Message::Ptr msg, Link * link = nullptr )
        { m_dynamicCastFunction( msg, link); }

protected:

    //! Construct Slot by derived class instance construction only
    Slot( const TypeDef& type, Function dynamicCastFunction,
          Function staticCastFunction ) :
        m_msgType(type),
        m_dynamicCastFunction(dynamicCastFunction),
        m_staticCastFunction(staticCastFunction)
    {
    }

    //! Insert link in set
    void connect( Link* link )
        { m_links.insert( link ); }

    //! Remove link from set
    void disconnect( Link* link )
        { m_links.erase( link ); }

    //! Set of active links
    LinkSet m_links;

    //! Type of accepted messages
    const TypeDef& m_msgType;

    //! Slot method usind dynamic cast on message pointer
    const Function m_dynamicCastFunction;

    //! Slot method using static cast on message pointer
    const Function m_staticCastFunction;
};


template <class TObj, class TMsg, 
          void (TObj::*TMethod)(typename TMsg::Ptr, Link*)>
class SlotT : public Slot
{
public:

    //! SlotT constructor with templated type
    SlotT( TObj* obj )
        : Slot(TMsg::Type(),
          std::bind( &SlotT<TObj,TMsg,TMethod>::dynamicCastFunction, obj,
                                      std::placeholders::_1,
                                      std::placeholders::_2 ),
          std::bind( &SlotT<TObj,TMsg,TMethod>::staticCastFunction, obj,
                                           std::placeholders::_1,
                                           std::placeholders::_2 ) )
    {
    }

private:
    //! dynamic cast function
    static void dynamicCastFunction( TObj* obj, 
                                     typename Message::Ptr msg, 
                                     Link* link )
    {
        typename TMsg::Ptr m = std::dynamic_pointer_cast<TMsg>(msg);
        if( m && obj )
            (obj->*TMethod)(m, link);
    }

    //! static cast function
    static void staticCastFunction( TObj* obj, 
                                    typename Message::Ptr msg, 
                                    Link* link )
    {
        typename TMsg::Ptr m = std::static_pointer_cast<TMsg>(msg);
        if( m && obj )
            (obj->*TMethod)(m, link);
    }    
};
于 2012-06-20T10:27:28.623 回答