2017-01-05 8 views
3

年前、私はC++についてよく知っていた前に、経験豊富なプログラマの同僚とイベントシステムの作成などについて話していました。 コールバックができるように関数ポインタを渡す必要性に重点を置いていたようです。C++、関数ポインタとオブザーバパターン

しかし、最近私は何らかのイベントシステムを実装する必要があるときは、単純に擬似インターフェイスクラスを構築し、それを継承してサブスクライバ/オブザーバパターンを使用してメソッドをオーバーライドしますイベントを配布します。

これまでのところ、これまで関数ポインタを使用する必要はほとんどありませんでしたが、確かに上記のような状況ではありません。私が本当に関数ポインタを使用しなければならなかった唯一の状況は、明示的に渡す必要があった他のユーザーの.dllと接続するときでした。

いつサブスクライバ/オブザーバパターンの代わりに関数ポインタを使用する必要がありますか?

どちらか一方を使うのは良いか悪いのですか? (おそらくオブザーバパターンが関数ポインタよりも優れていない場合があります)。

いくつかの洞察力を共有できますか?これについてもう少し経験を積んだほうがいいでしょうか? (前述の同僚は別のビジネスに移り、連絡がなくなりました)。私はこの主題に私の脳をぶつけ続け、観察者のパターンとインタフェースを使うのはそれほどうまくないとは思えません。

ありがとうございます!

(実際には動作しない場合があります、完全に私の頭の上から、検査せずに書かれた)、私はしばしば自分自身が書いて見つけるだろうクラスの例:

class NotifierListener { 

friend class Notifier; 
private: 
vector<NotifierListener*> mListeners; 

protected: 
void subscribe(NotifierListener* _subscriber) {mListeners->push_back(_subscriber);} 
virtual void onNotification(); 
} 

class Notifier : public NotifierListener { 

private: 
void doSomethingAndNotify() { 

... 
if (mListeners.size() > 0) { 
for (int i = 0; i < mListeners.size(); ++i) { 

mListeners[i]->onNotification(); 
} 
} 

} 
} 

class Something : public NotifierListener { 

Something() { subscribe(this); } 

void onNotification() { 

cout << "I got notified\n" << endl; 
} 
} 
+2

関数ポインタによるコールバックは、オブザーバパターンの実装も可能です。あなたの実装を示すいくつかのコードであなたの質問を説明する必要があります – wasthishelpful

+0

私は、コード例が価値と明快さを加えることに同意します。しかし、私の問題は、特定のコード実装の例を望むのではなく、「方法」ではなく「いつ」の一般的な言葉による説明にもっと興味があることです。 私は、仮想メソッドとして明白にはっきりと書かれていないほうがよいコードを書くことは本当に考えられません。 –

答えて

2

関数ポインタは少し効率的です。インターフェイスへのポインタを渡します。通常、インタフェースにはvtableへのポインタが含まれています。そのvtableには関数ポインタが含まれています。それは間接的な3レベルであり、参照のローカリティは貧弱です。

[*]他の実装も可能ですが、同様のオーバーヘッドがあります。

2

としてはwasthishelpful、継承とによって指摘されました関数ポインタは、オブザーバパターンを実装する2つの方法です。

関数ポインタ(または特にC++ 11のstd::functionのようなもの)を使用する主な利点は、柔軟性の向上です。監視クラスはインタフェースを実装する必要はなく、呼び出されるメンバ関数は任意に指定できます。独立した関数またはオブザーバー・インターフェースを実装するように変更したくないオブジェクトのメンバーを呼び出すこともできます。

一方、継承を使用する方が簡単で簡単です。しかしそれ以外にも、私は関数ポインタアプローチよりも利点があるとは思えません。

1

Observer Patternでは、リスナーはイベントの受信時に何らかの処理を行うエンティティです。ほとんどの場合、これらのエンティティは個別の作業を行い、イベントをリッスンし、の状態に応じて異なるアクションを呼び出すことができます。オブジェクトは個々の状態を持っているので、具体的なオブジェクトはリスナーでなければなりません。このような状態を、(関数ポインタを使用して呼び出される)純関数を使用して密接に/シームレスに維持するのは少し難しいです。