2010-02-09 28 views
4

我有一個靜態庫,我用C++編譯。我已將它分成許多頭文件和源文件。我想知道將庫的客戶端可能需要的所有頭文件包含在一個頭文件中是否更好,而這些頭文件又可以包含在其源代碼中,還是隻包含它們需要的頭文件?這會導致代碼不必要的膨脹?我不確定那些沒有被使用的類或函數是否仍然會被編譯到他們的產品中。我應該使用單個標題來包含所有靜態庫標題嗎?

感謝您的任何幫助。

回答

1

通常,鏈接最終可執行文件時,只有程序實際使用的符號和函數纔會被合併。您僅支付您使用的費用。至少這就是GCC工具鏈對我而言的作用。我不能說所有的工具鏈。

如果客戶端總是必須包含相同的頭文件集,爲了方便起見,我認爲可以提供包含其他頭文件的「主」頭文件。但要讓客戶也可以選擇只包含需要的內容。

爲了減少在大型項目的編譯時間,這是常見的做法包括頭儘可能的最小量,使單位編譯。

2

關於給兩個選項是什麼:

#include <library.hpp> // include everything 
#include <library/module.hpp> // only single module 

這樣您不必一個巨大的包含文件,併爲您的獨立文件,它們在一個目錄堆放整齊

2

這取決於庫,以及你如何構建它。記住一個庫的頭文件,以及哪個頭文件位於哪個頭文件中,實質上是庫的API的一部分。所以,如果你帶領你的客戶仔細挑選你的標題,那麼你需要長時間支持這種佈局。如果庫的某些部分是真正可選的並且很大,通過一個文件或僅僅幾個文件導出它們的整個接口是很常見的。

考慮的問題應該是編譯時間:如果客戶端必須包含二十個文件才能使用庫,並且這些文件包含內部包含,那麼如果經常使用,它可以顯着增加大型項目中的編譯時間。如果你走這條路線,確保你所有的包含文件內容都有適當的包圍,但包含的行也是如此。雖然注意:現代海灣合作委員會在這個特殊問題上做得很好,只需要標題內容的守衛。

至於膨脹最終編譯的程序,它取決於你的工具鏈,以及如何編譯庫,而不是庫的客戶端如何包括頭文件。 (需要注意的是,如果您在頭文件中聲明靜態數據對象,那麼即使客戶端不使用它,某些系統也會最終鏈接到定義該數據的對象中。)

總之,除非它是一個非常大的圖書館,或者一個非常古老而胡思亂想的工具鏈,我傾向於選擇單一的包裝。對我而言,將當前實現的部分凍結成頭部到圖書館的API是比其他人更大的擔心。

2

請記住,您編譯每個源文件包括編譯器的獨立調用。每次調用,編譯器讀取每一個包含頭文件,通過它解析,並建立一個符號表。

當您使用的這些中的一個「包括世界」頭文件在許多源文件,它可以顯著影響您的構建時間。

有辦法緩解這種情況;例如,微軟有一個預編譯的頭文件功能,基本上可以省去符號表以供後續編譯使用。

雖然有另一個考慮。如果我要使用你的WhizzoString類,我不必爲SOAP,OpenGL和你有什麼安裝標題。事實上,我寧願WhizzoString.h只包含屬於公共接口的類型和符號的標題(即我是將作爲你的類的用戶需要的東西)。

儘可能的,你應該嘗試從WhizzoString.h轉向包括對WhizzoString.cpp:

OK:

// Only include the stuff needed for this class 
#include "foo.h" // Foo class 
#include "bar.h" // Bar class 

public class WhizzoString 
{ 
    private Foo m_Foo; 
    private Bar * m_pBar; 
     . 
     . 
     . 
} 

更好:

// Only include the stuff needed by the users of this class 
#include "foo.h" // Foo class 

class Bar; // Forward declaration 

public class WhizzoString 
{ 
    private Foo m_Foo; 
    private Bar * m_pBar; 
     . 
     . 
     . 
} 

如果您的課程的用戶從不需要創建或使用欄類型,並且該類不包含任何欄Bar的實例,那麼在頭文件中只提供Bar的前向聲明就足夠了(WhizzoString.cpp將有#include "bar.h")。這意味着包括WhizzoString.h在內的任何人都可以避免包含Bar.h及其包含的所有內容。

+0

@斯科特史密斯:好點!謝謝! – csmithmaui 2010-02-11 04:46:14

相關問題