2016-06-22 42 views
0

我來自C#世界,所以事件和事件處理程序是日常的東西。 最近我一直在研究wxWidgets 我一直在搜索這個問題已經有一個星期了,我發現大多數C++程序員很難理解術語「事件」或「回調」,也許它在C++世界中是模棱兩可的。C++成員函數指針或事件驅動編程

下面是事件模型的一個簡單示例。

class A{ 
public: 
    A(){ 
     child.MySuperClickEvent = this.HandleSuperClick; 
    } 
private: 
    B child; 

    void HandleSuperClick(B child){ 
     // do stuff 
    } 
} 


class B{ 
public: 
    /*TBA*/ MySuperClickEvent; 
private: 
    void ClickPrivate(){ 
     MySuperClickEvent(this); 
    } 
} 

B類有它自己的指定目的,當它完成時觸發一個事件。 這個想法是,B類不應該有任何關於它的領域的知識,使它更可重用。

我已閱讀關於std :: function <>和函數指針。所有這些似乎都在處理靜態功能方面舉了一些例子,但只要「會員對會員」的言論開始變得油膩起來。

總之,問題很簡單。我如何製作一個可以從外部分配給成員的成員函數指針?

+0

什麼是「小孩」? – immibis

+0

更新了問題。這有意義嗎? – CyberFox

回答

0

有很多種方法可以實現這些功能,這些方法在內存開銷,支持多少回調,線程安全性, weak_ptr s到看是否存在參與仍然對象等。

就像一個味道,讓你開始 - 這裏有一個簡單的單線程「觀察員」的實施做基本上你的問題問什麼:

#include <iostream> 
#include <list> 

struct Observer 
{ 
    virtual ~Observer() { } 
    virtual void on_event_x() { } 
}; 

class Observable 
{ 
    public: 
    void add_observer(Observer& o) 
    { 
     observers_.push_back(&o); 
    } 

    void do_some_stuff() 
    { 
     std::cout << "before 1st event\n"; 
     fire_event_x(); 
     std::cout << "between 1st & 2nd events\n"; 
     fire_event_x(); 
     std::cout << "after 2nd event\n"; 
    } 

    private: 
    std::list<Observer*> observers_; 

    void fire_event_x() 
    { 
     for (auto& observer : observers_) 
      observer->on_event_x(); 
    } 
}; 

struct My_Observer : Observer 
{ 
    My_Observer(int id) : id_(id) { } 

    void on_event_x() override 
    { 
     std::cout << "My_Observer::on_event_x() id " << id_ << '\n'; 
    } 

    int id_; 
}; 

int main() 
{ 
    My_Observer my_observer_1 { 1 }; 
    My_Observer my_observer_2 { 2 }; 
    Observable x; 
    x.add_observer(my_observer_1); 
    x.add_observer(my_observer_2); 
    x.do_some_stuff(); 
} 

運行時輸出:

before 1st event 
My_Observer::on_event_x() id 1 
My_Observer::on_event_x() id 2 
between 1st & 2nd events 
My_Observer::on_event_x() id 1 
My_Observer::on_event_x() id 2 
after 2nd event 

如果不適合你功能,請準確說出爲什麼。

+0

謝謝你的時間。 「觀察者」這個詞對我來說很陌生。但是閱讀代碼:它看起來像是一種事件實現。但據我所見,你沒有附加任何回調/函數到這個「觀察者」,而是你繼承和重寫「on_event_x」函數。我會用這個解決方案修改一下 – CyberFox

+0

@Cyber​​Fox:不客氣。 [Observer](qt_config)是經典設計模式之一,值得學習 - 如果您有時間和興趣,「四人幫」一書[設計模式](https://en.wikipedia.org/wiki/Design_Patterns)會給你一個很好的,溫柔的介紹,以及其他非常常見的模式。正如你所說,我選擇說明的實現使用虛擬分發(C++的運行時多態的機制)而不是顯式函數指針或'std :: function <>'實例,但所有這些都是選項 - 後者是最靈活的,但後者是可選的'remove_observer()'變得更加棘手。 –

+0

我已經嘗試了大約一週的解決方案。我在模板中混合來製作一個通用的解決方案。但是,當模板和繼承被組合爲特定級別時,C++停止了類型推理或類似的事情。像迭代器無法找到循環變量。我不確定這是C++編譯器中的一個小故障還是我無能爲力。 (prolly後者) – CyberFox

0

由於這個問題被標記wxWidgets,讓我回答了它的更窄的變體,即如何使用成員函數作爲wxWidgets的事件處理程序:

這與Bind()方法的幫助下可以用做直接使用成員函數(您將指針傳遞給函數本身並將對象傳遞給它)或任何函數,即可以使用標準函數調用語法調用的任何函數,例如std::function<>對象,可以用來存儲任何可調用的對象。

+0

該文檔幾乎不提供足夠的信息,它們鏈接的事件示例是GitHub上的~600行文件。你能提供一個簡單的例子嗎? – CyberFox

+0

對於你感興趣的功能,你甚至應該能夠對6000行樣本進行掃描,但是讓我[做這個](https://github.com/wxWidgets/wxWidgets/blob/v3.1.0/samples/)事件/ event.cpp#L514)。 –

+0

我可能可以導航6000行C#代碼。所以是的,我真的應該得到那匹馬。我也在「Bind」上找到了帶有ctrl + f的第514行。但我仍然有點迷路。 wxEVT_BUTTON全局常量。這只是一個數字。文檔中提到了EventType,但這真的意味着什麼?如果我定義了一個不同的常量,它會附加到不同的事件。或者我放在那裏沒有關係? – CyberFox