2012-09-01 63 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。然而,這是很難實現的,並易折斷......