简体   繁体   中英

C++ cyclic dependency using class templates - how to refactor?

I am dealing with a cyclic dependency problem in C++.

The situation looks like the following:

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

There is a cyclic dependency because libA uses the Converter-Class from libB and libB needs to now about the Object-Types of libA that need to be converted - since DataConverter::convert returns a Body or Header object.

I thought about solving this issue with forward declarations - but that does not seem to be the cleanest solution to me. All in all my plan was to provide an extensible DataConverter solution.

What would you guys suggest as best practice? A complete different design is also welcome :)

Best, Sebastian

If you need a class template DataConverter , then this cannot be part of any compiled library. It has to be available via include files. Once you put the DataConverter code in a header, used by both libA and libB your cyclic dependency disappears.

Your design seems to be flawed. If two libraries, named A and B, are dependent on each other, it means that they must always be shipped together. If they must always be shipped together, it means that they are logically part of the same interface. It means that in fact, you have only one library.

There is not enough information to tell what would be the best solution, but here are some tips:

  1. Merge these libraries.
  2. Make one library dependent on the other one, for example, by moving DataConverter to libA.
  3. Create a utility library, dependent on these two.
  4. Create an appropriate interface in libB, using templates or virtual classes, and make libA dependent on libB. The latter (virtual classes) is very likely to be a better choice in dynamically-linked library.

您可能想要创建定义接口的抽象基类,并相互隐藏实现(派生类)。

Some alternatives:

  1. DataConverter as a fully generic implementation which will be instantianted in libA.so with proper types at compile time. This were a typical c++-ish solution. Your "convertable" types from libA (or others) would have to satisfy some Convertable concept which the fully templatized implementation of DataConverter would be using

  2. Dependency inversion, as proposed by JohnB. You'd basically accomplish the same goal, but with interfaces, implementations and registration/resolving at runtime. A lot more of work to do, but scalable, ABI achievable, deployable as library etc...

  3. Some kind of clever combination of both, something like Boost.Serialization . This is however difficult to achieve and easy to break...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM