C++信號槽

什麼是信號槽?

  • 簡單來講,信號槽是觀察者模式的一種實現,或者說是一種昇華。
  • 一個信號就是一個可以被觀察的事件,或者至少是事件已經發生的一種通知;一個槽就是一個觀察者,一般就是在被觀察的對象發生改變的時候——也能夠說是信號發出的時候——被調用的函數;你能夠將信號和槽鏈接起來,造成一種觀察者-被觀察者的關係;當事件或者狀態發生改變的時候,信號就會被髮出;同時,信號發出者有義務調用全部註冊的對這個事件(信號)感興趣的函數(槽)。
  • 信號和槽是多對多的關係。一個信號能夠鏈接多個槽,而一個槽也能夠監聽多個信號。
  • 另外信號能夠有附加信息。

使用信號槽

  • 信號槽是偉大的工具,可是如何能更好的使用它?相比於直接函數調用,有三點值得咱們的注意。c++

    • 一個信號槽的調用,可能會比直接函數調用耗費更多的時間/空間;
    • 可能不能使用 inline;
    • 對於代碼閱讀者來講可能並不友好。
  • 使用信號槽進行解耦,咱們得到的最大的好處是,鏈接兩端的對象不須要知道對方的任何信息。
  • 你能夠實現一個應用程序,其中每個函數調用都是經過信號來觸發的。這在技術上說是徹底沒有問題的,然而倒是不大可行的,由於信號槽的使用無疑會喪失一部分代碼可讀性和系統性能。如何在這其中作出平衡,也是你須要考慮的很重要的一點。

sigslot庫

  • 官方地址
  • C++中的信號槽系統經常使用的有三種:boost的signals,sigslot,sigc++。其中sigslot庫是比較簡單好用的。
  • sigslot是一個線程安全、類型安全,用C++實現的sig/slot機制(sig/slot機制就是對象之間發送和接收消息的機制)的開源代碼庫。只有一個頭文件sigslot.h。
  • 基本功能有:安全

    1. connect
    2. disconnect
    3. emit
  • sigslot優勢多線程

    1. 不用擔憂空回調,當回調對象析構時會自動disconnect
    2. 支持多線程,線程安全,有鎖
  • sigslot缺點架構

    1. 只能回調void類型函數,不支持返回值。boost中的signals庫架構相似,支持返回值,但引入了boost中的其餘庫
    2. slot沒有優先級,不能動態調整回調隊列中的前後順序
  • slot函數(被回調的函數)就是普通的成員函數,但有如下限制:函數

    1. 返回值必須爲void
    2. slot參數個數範圍爲0-8個
    3. 實現slot的類必須繼承自has_slots<>
  • 前兩條是sigslot庫做者的限制,做者權衡各方面因素後作出的決定,若是你以爲有必要你能夠修改sigslot代碼取消該限制,而最後一條是sigslot的機制基礎,必須遵照,除非你本身從新寫個sigslot。
  • 須要注意的是:sigslot庫的設計,當發送一個沒有鏈接的信號時,不作任何處理,也不會有錯誤發出。

基本使用方式

  • 包含頭文件
#include "sigslot.h"
  • 改動(「typename 必須前置於嵌套依賴類型名」)
//在sigslot.h的420,將:
typedef sender_set::const_iterator const_iterator;
    //改成:
typedef typename sender_set::const_iterator const_iterator;
  • signal0~signal8:信號類:做爲類成員
class mySg
{
    sigc::signal0<>                 sg1;    // 無參數
    sigc::signal2<char*, double="">    sg2;    // 2個參數
}
  • connection(槽函數:做爲類成員,類須要繼承has_slots<>,且槽函數的返回值必須是void類型)
class mySlot: public : has_slots<>
{
public:
    void on_func1(){}                       // 無參數,與信號對應
    void on_func2(char*, double)(){}        // 2個參數
};
mySg    sig;
mySlot  slt;
sig.sg1.conncent(&slt,&mySlot::on_func1);
sig.sg2.conncent(&slt,&mySlot::on_func2);
  • disconnection(解除鏈接:能夠使用disconnect()和disconnect_all())
sig.sg1.disconnect(&slt);
sig.sg1.disconnect_all();
  • emiting(發送信號:能夠直接使用()運算符,也能夠調用signal的emit函數)
sig.sg1.emit();
sig.sg2("str",0.1);
相關文章
相關標籤/搜索