2012-09-01 90 views
0

我正在处理C++中的循环依赖问题。使用类模板的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 

有一个循环依赖,因为力霸从libB使用转换器级和libB需要到现在的力霸的需要进行转换的对象类型 - 因为DataConverter :: convert返回一个Body或Header对象。

我想过用前向声明来解决这个问题 - 但这对我来说似乎并不是最干净的解决方案。总而言之,我的计划是提供可扩展的DataConverter解决方案。

你们会提出什么样的最佳做法?一个完整的不同的设计也欢迎:)

最佳, 塞巴斯蒂安

+0

这看起来像内存泄漏给我 - 你几乎可以肯定要'DataConverter ().convert(数据)',没有'new'(除非'convert'以'delete this'结尾,但那会很可怕)。 –

+0

它比任何其他东西更伪代码:) –

回答

1

您可能希望创建定义接口抽象基类和隐藏彼此的实现(派生类)。

+0

好吧 - 那么定义一个AbstractConverter工厂,实际上是返回指定的模板目标格式的具体实现。但是,这将如何解决我的依赖问题? –

+1

定义包含转换器所需的所有方法(抽象)的抽象类。你可以在头文件中做到这一点。将这个头文件包含在liba.so和libb.so的源代码中。 libb中的转换器(几乎可能)从抽象类派生。 libb包含两个返回转换器的工厂方法,并且这些工厂方法在liba中声明为extern。因此libb知道liba,但是liba现在没有关于libb。 – JohnB

8

如果您需要类模板DataConverter,那么这不能是任何编译库的一部分。它必须通过包含文件可用。一旦将DataConverter代码放入标头中,libAlibB都会使用您的循环依赖关系消失。

3

您的设计似乎有缺陷。如果名为A和B的两个库相互依赖,则意味着它们必须始终一起发货。如果它们必须始终一起发货,则意味着它们在逻辑上是同一接口的一部分。这意味着实际上你只有一个图书馆。

没有足够的信息来告诉什么是最好的解决办法,但这里有一些提示:

  1. 合并这些库。
  2. 使一个库依赖于另一个库,例如,通过将DataConverter移动到libA。
  3. 创建一个实用程序库,取决于这两个。
  4. 使用模板或虚拟类在libB中创建适当的接口,并使libA依赖于libB。后者(虚拟类)很可能是动态链接库中更好的选择。
1

一些替代方案:

  1. DataConverter作为一个完全通用的实现将在libA.so适当类型在编译时instantianted。这是一个典型的C++ - ish解决方案。您的“可转换”从力霸(或他人)的类型,将必须满足一些Convertable概念DataConverter完全模板化的实现将使用

  2. 依赖倒置其建议,由JohnB。你基本上可以实现相同的目标,但是可以在运行时使用接口,实现和注册/解析。还有很多工作要做,但是可扩展的,ABI可实现的,可以部署为图书馆等等。

  3. 某种巧妙的组合,像Boost.Serialization。然而,这是很难实现的,并易折断......