web-dev-qa-db-ja.com

ライブラリIO:インターフェイスクラスまたはコールバックを使用しますか?

C++でストリームデータを処理する小さなライブラリ(kLOCが少ない)を構築しています。ストリーミングされたデータから(パケットで)ライブラリはデータベースを1つずつコンパイルし、当然その情報をホストアプリケーションに戻す必要があります。

これは私の最初のライブラリなので、API /インターフェイスの処理方法がわかりません。私の知る限り、CPPの「インターフェース」またはCスタイルのコールバックのどちらを使用するかを選択できます。この質問は、プログラミングの側面だけでなく、バ​​ージョン間のライブラリAPIの管理の側面にも関連しています。

なぜインターフェースを使用するのですか?

  • インターフェイスは一度宣言され、APIの変更はそのクラスに直接反映されます
  • ライブラリはコンパイルされないので、メソッドやイベントを忘れることはできません
  • Cスタイルのコールバックより「クリーン」なC++
  • ライブラリ内で何をしているのか確信があり、「多分複雑な」ものを戻り値の後ろに隠します

インターフェースの使用

class InterfaceClass {

public: 

    virtual bool isDataBlockComplete(...) = 0;
    virtual bool isDataBaseUpdated(...) = 0;
    virtual bool hasEventCompleted(...) = 0;
    [..]
}


/* User code */

class SomeClass : InterfaceClass { [..] }

bool SomeClass::hasEventCompleted(...){ /* check */ }

SomeClass *instance = new SomeClass();

InterfaceClass *instance = new InterfaceClass();

if(instance->hasEventCompleted) [..]

for(i = 0; i < instance->getQueueSize(); i++ ) [..]

なぜCスタイルのコールバックを使用するのですか?

  • 実行時に登録および更新できます
  • この方法でイベントを「購読」できます
  • 後でCラッパーを提供するのに役立ちます
  • 私が書いたりテストしたりする必要のあるコードが少ないため、処理速度が大幅に向上します。

コールバックの使用

class InterfaceClass {

public:

    registerCallback( void *f, tEvent event);
    deregisterCallback(tEvent event);
}


/* User code */

void myfunc(){ .. }

instance->registerCallback(&myfunc, SOME_EVENT);

/* Gets called by the governor / observer of library */

したがって、これは優先度の問題ではなく、ライブラリに使用する「スタイル」の問題です。ネットで何も見つかりませんでした(仮想抽象クラスの使用の技術的側面やコールバックの実装方法を中心に展開しているようですが、実際に上記で質問したことについて誰も議論していません)。単語の組み合わせの)。

このような種類のライブラリにはどのスタイルが適しているのでしょうか。それはなぜですか。 「プロフェッショナル」ライブラリはメインアプリケーションとどのように通信しますか? (SEには広すぎるかもしれませんが、とにかく試してみてください:))

4
Jan Krüger

C++コードではCスタイルのコールバックを使用しないことをお勧めします。 C++は同等のイディオムを提供し、型の安全性を高め、読みやすく(少なくともほとんどのC++開発者にとって)、コンパイラーにコードを最適化する機会を提供します。また、ラムダ関数を使用して、呼び出しサイトでの動作を定義することもできます。これは、関数ポインターでは実現できません。これは、std::functionヘッダーの<functional>テンプレートクラスです。

これを使用すると、コードは次のようになります。

class InterfaceClass {

public:
   registerCallback(std::function<void(MyEvent)> callback, tEvent event);
   deregisterCallback(tEvent event);
};

instance->registerCallback ([] (MyEvent evt) { 
                               /* do something here */ 
                            }, SOME_EVENT);
1
Periata Breatta

オブザーバーパターン を検討することをお勧めします。実行時にイベントリスナー(オブザーバー)を登録および登録解除できます。

3
Q Q