2011-01-27 109 views
47

對於如何避免頭文件的循環依賴關係有什麼建議嗎?避免頭文件的循環依賴關係

當然,從一開始,我儘量設計項目儘可能透明。但是,隨着越來越多的功能和類被添加,並且項目變得越來越不透明,循環依賴開始發生。

是否有任何通用,驗證和工作規則?謝謝。

回答

48

看你是否有循環依賴,那麼你做錯了什麼。

至於例如:

foo.h 
----- 
class foo { 
public: 
    bar b; 
}; 

bar.h 
----- 
class bar { 
public: 
    foo f; 
}; 

是違法的,你可能想:

foo.h 
----- 
class bar; // forward declaration 
class foo { 
    ... 
    bar *b; 
    ... 
}; 

bar.h 
----- 
class foo; // forward declaration 
class bar { 
    ... 
    foo *f; 
    ... 
}; 

這是確定的。

一般規則:

  1. 確保每頭可以被包含在它自己的。
  2. 如果您可以使用正向聲明,請使用它們!
+0

+1你好Artyom,謝謝你的回覆。更頻繁地使用前向聲明可能會有所幫助。 – 2011-01-27 13:49:11

+0

@Artyom:如果指針是爲了擁有資源,我建議使用`scoped_ptr`或`unique_ptr`。如果指針僅僅是一個對象的引用,那麼可能有必要使用Observer模式,以便每當引用的對象被銷燬時它就「未設置」。 – 2011-01-27 14:16:01

4

根據您的預處理器功能:

#pragma once 

#ifndef MY_HEADER_H 
#define MY_HEADER_H 
your header file 
#endif 

如果你覺得很無聊,設計的頭文件從Hwaci(SQLite和化石DVCS的設計師)也許makeheaders可能是對你的興趣。

+2

這與其說是爲了避免循環依賴,以避免錯誤「符號重新定義」。儘管如此,這是一個標準的,絕對需要的練習。 – 2011-01-27 13:19:35

+0

你好Benoid,是的,我不得不同意Peter Torok。這在每本教科書和必須使用的遊戲中都有所解釋。非常感謝您的回覆。 – 2011-01-27 13:59:27

6

一般的方法是將共同性分解成第三個頭文件,然後由兩個原始頭文件引用它們。

Circular Dependency Best Practice

+0

+1嗨,Ed,這是另一個非常好的建議。謝謝。 – 2011-01-27 13:49:55

+0

我檢查了你提供的鏈接,它顯示了重新設計分類以避免循環依賴的好例子。 – 2011-01-27 14:18:14

+0

謝謝,我也喜歡它;-) – 2011-01-27 14:34:00

3

你想要的是一個layered approach。您可以定義哪些模塊可以依賴於較低層模塊,但是應該使用observers。現在您仍然可以定義圖層的細粒度以及是否接受圖層中的循環依賴關係,但在這種情況下,我會使用this

15
  • 在可能的情況下使用前向聲明。
  • 如果只有cpp文件需要,則將任何頭文件移出頭文件並移入相應的cpp文件。執行此操作最簡單的方法是使#include "myclass.h"首先包含在myclass.cpp中。
  • 在不同類之間的交互點引入接口可以幫助減少依賴關係。
3

在一般的頭文件應該正向聲明,而不是包括其他頭,只要有可能。

還要確保您堅持每個標題一個類。

那你幾乎肯定不會出錯。

最糟糕的耦合通常來自臃腫的模板代碼。由於必須在頭文件中包含定義,因此通常會導致必須包含各種頭文件,然後使用該模板的類將包含模板頭文件,其中包含大量其他內容。

因此,我通常會說:小心模板!理想情況下,模板不應該在其實現代碼中包含任何內容。

6

我跟着避免循環依賴一些最佳做法,

  1. 玉碎OOAD原則。除非包含的類與當前類具有合成關係,否則不要包含頭文件。改用前向聲明。
  2. 設計抽象類來充當兩個類的接口。通過該接口進行類的交互。