2009-12-23 89 views
3

假設所有標頭都被守護,假設您有一個抽象數據類型。你應該依賴另一個包含頭部的頭部嗎?

#include "that.h" 
#include "there.h" 

class Foo { 
protected: 
    // Functions that do stuff with varOne and varTwo 
private: 
    that varOne; 
    there varTwo; 
... 
}; 

然後在從foo繼承的類(因此包含foo.h),你是否也打擾包括這個和這個?通常我所做的就是包括一個班級需要的所有東西,而不管是否已經從另一個包含中接收它們。這是多餘的嗎?

回答

3

冗餘地包含否則直接包含的頭文件有一個缺點:它強制編譯器重新打開並重新解析它們。例如,在

啊:

#ifndef __A_H 
#define __A_H 
// whatever 
#endif 

BH:

#ifndef __B_H 
#define __B_H 
#include "a.h" 
// whatever 
#endif 

c.cpp:

#include "a.h" 
#include "b.h" 
//whatever 

啊已經被打開,讀兩次 - 雖然#ifndef將使預處理忽略ah的第二個inc中的內容它仍然必須至少從磁盤加載文件並將其字節從#ifndef讀取到#endif

這會降低編譯速度。它不會破壞你的構建或任何東西,但它只是一個非常大的項目中的煩惱,編譯可能需要很多分鐘。

如果您在頭文件中使用#pragma once,知道的編譯器很有可能會將文件名緩存在較高級別,並且完全忽略第二個包含的a.h。這也可以加速構建。

+0

謝謝。我考慮過這一點,但並不認爲這樣的解讀會顯着減慢編譯速度。 – Anonymous 2009-12-23 04:22:57

+0

我聽說過(http://www.efnetcpp.org/wiki/Include_guards)gcc和其他編譯器可能會緩存頭文件並自動識別包含的警衛。對此的性能損失可能可以忽略不計。 – 2009-12-23 04:25:00

+0

這取決於項目的大小。對於需要兩分鐘編譯的內容,您將不會注意到其中的差異。對我們來說,我們每年進行一次#包括依賴性春季清潔,通常會在30分鐘內重建5-10分鐘。我聽說有些人甚至進一步採取這一步 - 而不是像編譯後鏈接的300個.cpp文件那樣,它們有6個.cpp文件,其中每個文件包含50個,因此編譯器會處理用更少的單位。他們已經說過它的編譯時間減半了,但在我們的例子中,它將編譯器的內存廢掉了! – Crashworks 2009-12-23 04:27:25

0

這取決於你真的。如果顯然超級類包含了它們(即不查看它的頭部),那麼省略#include將是有意義的。當然,你可以自由添加它們以保證安全。

+0

好的謝謝。我不認爲這是一件大事,只是有興趣,如果有任何有效的論據反對它。看起來沒有。 – Anonymous 2009-12-23 03:24:47

0

這不一定是多餘的。事實上,你有獨立的頭文件和源文件意味着只要源文件爲頭文件提供定義,就可以交換src和頭文件。

.h文件應該只包含標題中使用的內容。例如,如果標題中沒有io聲明,則不需要stdio,而應該僅在src文件中使用,例如,如果它使用printf。

但是可能會出現這樣的情況,您可以使用一個標頭需要特定的包含,而另一個標頭不會(例如,當一個標頭比另一個標頭更具限制性時),在這種情況下,最好重複.h包括。

由於它被守護,所以它對你生成的最終對象/ exe沒有任何影響,並且它不會增加編譯時間,因爲它包含了一些值得擔心的事情,所以最好包含它們以防萬一你想使用不同的.h文件在某些​​時候。

編輯:更具體的例子 inc1.h

#ifndef INC1_H 
#define INC1_H 
inc1_struct {                
    int x; 
}; 
#endif 

inc2.h

#ifndef INC2_H 
#define INC2_H 
#include "inc1.h" 
void inc2_f(); 
struct inc1_struct *inc2_callinc1(); 
#endif 

prog.cpp 的#include 「inc1.h」 的#include 「inc2.h」
#include #include

void inc2_f() { 
    printf("inc2_f\n"); 
} 

struct inc1_struct *inc2_callinc1() { 
    return (struct inc1_struct*) malloc(sizeof(struct inc1_struct)); 
} 

int main(int argc, char **argv) { 
    struct inc1_struct *s = inc2_callinc1(); 
    return 0; 
} 

這將編譯,但可以說你不想暴露

struct inc1_struct *inc2_callinc1(); 

在inc2.h

這樣你就不會需要包括在inc2.h文件inc1.h,但如果你不想在prog.cpp中刪除inc2_callinc1()的定義,那麼你需要包含inc1.h.

1

根據我的經驗,最好在Foo.h中轉發declare而不是包含它們,因爲它們在技術上並不需要,因爲它們是通過引用傳遞的。

在這種凱德,foo.h中會是什麼樣子:

class that; 
class there; 

class Foo 
{ 
    public: 

     void func(that &param) = 0; 
     void funcTwo(there &param) = 0; 
     ... 
}; 
+0

謝謝。愚蠢的錯誤,我會讓這個例子更現實一些。 – Anonymous 2009-12-23 03:38:36

0

然後在從 foo的繼承類(因此包括FOO。h), 你還打擾包括和 這個?

通常,我會爲標題直接使用的任何類型包含標題(帶有防護)。

不過,我經常丟棄了其中的基類必須已包括他們因爲被覆蓋的成員函數原型的派生類 - 這是真實的這個,在你的榜樣

最終它是你的選擇,但你也可以考慮你認爲標題有多大可能改變 - 因爲這是唯一真正重要的時刻。

1

問題是,你最終會以這種方式在你的obj文件中包含額外的東西。標頭警衛不會阻止這一點。你引用的任何東西都必須在你的對象中,所以不要只有很多標題,包括其他標題,然後在其他地方包含它。如果你的頭文件很潦草,並且有很多文件,你很快就會遇到代碼量變大,編譯時間變慢的問題。

相關問題