2012-06-18 22 views
0

我正在尋找一種方法來避免在以下問題中進行系統動態強制轉換。動態連接C++方法與動態強制轉換如果需要

我有行動的對象和消息對象。 Action對象具有發送消息的方法以及接受消息的其他方法。當然有派生的Action類和消息類。基於定義互連對象網絡的配置文件,對象及其方法在運行時通過字符串標識動態連接。

這等同於對自變量的數目和類型強烈約束的信號槽系統。所有信號都會發出派生類消息的消息,並且所有插槽接受從類消息派生的消息。

連接是NxN。因此信號是多播的,並且時隙可以接受來自多個源的信號。

當前的實現是使用Link類實例化一個信號和槽之間的連接。信號和插槽是函數成員變量。每個Action對象都有兩個映射。一個從字符串名稱到信號,另一個從字符串名稱到插槽。還有一個Action名稱的全球地圖。跟蹤目標操作(插槽)中鏈接的好處是在實例被銷燬時正確斷開所有鏈接。

在第一遍在配置文件中定義的所有操作情況下被實例化,在第二遍中的鏈接被實例化的連接信號槽。

的問題是,你將如何實現這個,所以如果需要一個動態轉換時,才執行,當鏈接被實例化,這樣才執行的消息類型匹配檢查和。例如,如果我們具有消息基類M和M1的子類M1和M1的子類M2,則從信號(M2)到時隙(M1)或時隙(M)的鏈路不會執行動態演員陣容,並且從信號(M1)或信號(M)到時隙(M2)的鏈路將執行動態演播。只有在動態轉換成功(不返回nullptr)時才調用slot方法。

其中動態鑄造在每個呼叫執行的實現是微不足道的。如果可能的話,我尋求解決方案來避免這種情況

我目前的理解是,由於動態綁定,我不能使用boost :: signals。

+0

請問爲什麼你絕對想要擺脫'dynamic_cast <>'s? – ereOn

+1

我想這是一個表現的事情。但是,無論如何,我都有點難以理解爲什麼它是必需的。你能提供一個代碼示例來展示你的意思嗎? – Stefan

+1

對於這種用例,它聽起來像你應該使用虛擬功能而不是動態轉換。 – Ben

回答

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; 
}; 

這裏是時隙和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); 
    }  
};