0

C++ での循環依存の問題を扱っています。

状況は次のようになります。

libA.so:
    - Body.cpp
    - Header.cpp
    - DataObject.cpp
    - DataObject::read(boost::asio::streambuf* data)
      {
          boost::asio::streambuf data;

          ....

          body = (new DataConverter<Body>)->convert(&data);
          header = (new DataConverter<Header>)->convert(&data);
      }

  libB.so:
      - DataConverter.cpp
          -> DataConverter<T>
          -> T* DataConverter<T>::convert(boost::asio::streambuf* data)

  libA.so <-> libB.so

libA は libB の Converter-Class を使用し、libB は変換する必要がある libA のオブジェクト タイプについて必要があるため、周期的な依存関係があります。これは、DataConverter::convert が Body または Header オブジェクトを返すためです。

この問題を前方宣言で解決することを考えましたが、それは私にとって最もクリーンな解決策ではないようです。全体として、私の計画は拡張可能な DataConverter ソリューションを提供することでした。

ベストプラクティスとして何を提案しますか? 全く違うデザインも大歓迎です:)

ベスト、セバスチャン

4

4 に答える 4

8

クラス テンプレートが必要な場合DataConverter、これをコンパイル済みライブラリの一部にすることはできません。インクルードファイルを介して利用できる必要があります。DataConverterコードをヘッダーに配置するlibAと、両方で使用されlibB、循環依存関係がなくなります。

于 2012-09-01T10:29:48.610 に答える
3

あなたのデザインには欠陥があるようです。A と B という名前の 2 つのライブラリが相互に依存している場合、それらは常に一緒に出荷する必要があることを意味します。常に一緒に出荷する必要がある場合は、それらが論理的に同じインターフェイスの一部であることを意味します。これは、実際にはライブラリが 1 つしかないことを意味します。

何が最善の解決策かを判断するのに十分な情報はありませんが、いくつかのヒントを次に示します。

  1. これらのライブラリをマージします。
  2. たとえば、DataConverter を libA に移動して、1 つのライブラリを他のライブラリに依存させます。
  3. これら 2 つに依存するユーティリティ ライブラリを作成します。
  4. テンプレートまたは仮想クラスを使用して libB に適切なインターフェイスを作成し、libA を libB に依存させます。後者 (仮想クラス) は、動的にリンクされたライブラリでより適切な選択になる可能性が非常に高くなります。
于 2012-09-01T11:58:34.427 に答える
1

インターフェイスを定義する抽象基本クラスを作成し、実装 (派生クラス) を互いに隠したい場合があります。

于 2012-09-01T10:26:14.147 に答える
1

いくつかの代替案:

  1. DataConverterコンパイル時に適切な型で libA.so にインスタンス化される完全に汎用的な実装として。これは典型的な C++ っぽいソリューションでした。libA(またはその他)からの「変換可能な」型は、完全にテンプレート化された実装が使用するいくつかのConvertable概念を満たす必要がありますDataConverter

  2. JohnB によって提案された依存関係の逆転。基本的に同じ目標を達成できますが、インターフェース、実装、および実行時の登録/解決が必要です。やるべきことはもっとたくさんありますが、スケーラブルで、ABI を達成可能で、ライブラリとしてデプロイ可能です...

  3. のような、ある種の巧妙な両方の組み合わせBoost.Serialization。しかし、これは達成するのが難しく、簡単に破ることができます...

于 2012-09-01T12:20:28.250 に答える