2016-06-22 22 views
0

私はC#の世界から来ており、イベントとイベントハンドラは毎日のものです。 最近、私はwxWidgetsについて勉強していました 私は1週間これについて調べており、ほとんどの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 <>と関数ポインタについて読んだことがあります。これは静的な機能を扱う際にすべての事例を取っているようですが、「Member to Member」のことが話題になるとすぐに、油断してしまいます。

要約すると、問題は簡単です。外部にメンバーに割り当てることができるメンバー関数ポインタを作成するにはどうすればよいですか?

+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)は古典的なデザインパターンと価値のある学習の1つです。時間と関心があれば、「Gang of Four」ブック[Design Patterns](https://en.wikipedia.org/wiki/Design_Patterns)それと他の非常に一般的なパターンへの良い、優しい導入をあなたに与えるでしょう。あなたが言うように、私が示した実装では、明示的な関数ポインタや 'std :: function <>'インスタンスではなく、仮想ディスパッチ(C++の実行時ポリモーフィズムのメカニズム)を使用しますが、それらはすべてオプションです。 'remove_observer()'はやりにくくなります。 –

+0

私は約1週間あなたの解決策を試しました。私はジェネリックなソリューションを作るためにTemplatesで混合しました。しかし、テンプレートと継承があるレベルで結合されているようで、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/event.cpp#L514)を参照してください。 –

+0

〜6000行のC#コードをナビゲートすることができるかもしれません。だから私は本当にその馬に乗るべきです。私は "バインド"でCtrl + Fキーで514行目を見つけました。しかし、私はまだ少し失われています。 wxEVT_BUTTONグローバル定数。それは単なる数字です。ドキュメントにはEventTypeと書かれていますが、それは実際には何を意味していますか?別の定数を定義すると、別のイベントにアタッチされます。それとも私がそこに置いたかは重要ではありませんか? – CyberFox

関連する問題