2010-05-14 61 views
10

在我的C++項目中,何時必須使用頭文件的包含(#include "myclass.h")?何時必須使用班級的前向申報(class CMyClass;)?頭文件包含/前向聲明

+1

見http://stackoverflow.com/questions/553682/when-to-use-forward-declaration – ChrisN 2010-05-14 08:26:53

回答

16

通常首先嚐試前向聲明。這將減少編譯時間等。如果不編譯去#include。如果您需要執行以下任何操作,您必須去#include:

  1. 訪問類的成員或函數。
  2. 使用指針算術。
  3. 使用sizeof。
  4. 任何RTTI信息。
  5. new/delete,複製等
  6. 按值使用它。
  7. 繼承它。
  8. 成爲會員。
  9. 實例中的功能。

(6,7,8,9-從@Mooing鴨)

他們很可能更多,但我沒有得到今天我的語言法的帽子。

+4

你還需要將之列入按價值使用它。所以如果你從它繼承,把它作爲一個成員,或者在一個函數中有一個實例。 – 2012-01-13 19:08:34

10

如果你只需要一個指針類,你不需要對任何類的知識,而不是它的名字,你可以使用向前聲明。

2

作爲初學者,當你需要使用它們包含的類型或函數時,你應該總是#include頭文件 - 不要試圖通過向前聲明東西來「優化」你的構建 - 即使在大型項目,只要項目設計良好。

唯一的一次,你絕對需要預先聲明是這樣的情況:

struct A { 
    void f(B b); 
}; 

struct B { 
    void f(A a); 
}; 

每個結構(或類)是指其他的類型。在這種情況下,你需要B的前向聲明來解決問題:

struct B; // forward declaration 

struct A { 
    void f(B b); 
}; 

struct B { 
    void f(A a); 
}; 
+0

對具有一個大的「forward_declarations.h」文件的大型項目進行維護可能是一場噩夢,因爲它經常混淆開發工具,並且很難瀏覽不熟悉的代碼庫。儘管減少代碼中的耦合有時很重要,但不要自動將每個類都放入一個前向dec文件中。 – bd2357 2016-02-09 16:27:49

2

你應該努力朝這既是爲了減少編譯時間也與模塊化和可測試性,以幫助減少你的#include秒。正如@ypnos所說,當你只需要指針時,類轉發就非常出色。

有關如何減少頭部依賴一些實用的技巧,例如見this article

11

有幾個問題轉發聲明:

  • 這就像在多個地方存儲你的類名 - 如果你改變它在一個地方,你現在必須改變它在其他地方。重構成爲一個挑戰,因爲代碼仍然可以用更改的類名正確編譯,但由於前向聲明指向未定義的類,因此鏈接將失敗。如果包含頭文件並且不使用前向聲明,則在編譯期間會捕獲這些問題。
  • 前向聲明很難讓其他人維護。舉例來說,如果一個頭文件包含:

    include "MyProject/MyWidgets/MyFooWidgets/FooUtil/Foo.h" 
    

    ,而不是向前聲明

    class Foo ; 
    

    很容易讓別人找到類Foo聲明那裏。有了前瞻性聲明,這不是 明顯;當用戶試圖打開 變量的聲明時,Eclipse等一些IDE可能會打開前向聲明。

  • 當您在包含前向聲明的代碼中包含頭文件但實際代碼定義位於您未鏈接的某個其他庫中時,鏈接可能會因未定義的符號錯誤而失敗。在編譯時遇到這個問題比如"Could not find file MyProject/MyWidgets/MyFooWidgets/FooUtil/Foo.h"這樣的錯誤更方便,因爲那樣您就會知道在哪裏查找相應的Foo.cpp並確定包含它的庫。

如果您認爲您的構建時間過長,則嘗試僅在沒有鏈接的情況下進行編譯。如果你的代碼需要10秒的時間來編譯,10分鐘的時間來鏈接,這個問題與一些額外的包含無關。同樣,如果你的頭文件包含很多東西,它實際上會導致性能問題,那麼你可能需要將該文件的內容重構爲多個較小的頭文件。

那麼什麼時候可以轉發聲明?如果你在真正的聲明中使用相同的頭文件。

例子:

class Foo ; 

typedef Foo* FooPtr ; 
typedef Foo& FooRef ; 

class Foo 
{ 
    public: 
     Foo() ; 
     ~Foo() ; 
} 

OR

class TreeNode ; 

class Tree 
{ 
private: 
    TreeNode m_root ; 
} 

class TreeNode 
{ 
    void* m_data ; 
} ; 
+1

我同意@David列出的前向聲明問題。但我不同意這個結論:「那麼什麼時候可以轉發聲明呢?如果你在與真實聲明相同的頭文件中進行聲明。」正如其他人所指出的,前向聲明是分離物理佈局並加快構建的重要工具。 //越來越多我不知道我們是否應該#include「Foo.hf」 - .hf爲「除正向聲明外不包含任何內容的頭文件」。 //當然,我會自動生成。 – 2012-10-15 22:06:29