簡體   English   中英

在頭文件與實現(.cpp)文件中定義構造函數

[英]Defining constructor in header file vs. implementation (.cpp) file

我可以在類.h文件或實現文件.cpp中定義類構造函數的主體。 對於特定項目中的編譯器而言,這兩種樣式可能是相同的(對我而言,項目意味着DLL )。 同樣適用於任何成員函數:它們可以在頭文件中定義,也可以在那里聲明,然后在cpp文件中定義。

但是,我發現如果我需要在不同的項目中包含這樣的類頭文件(意味着最終使用頭文件的代碼最終在不同的DLL中 ),那么在頭文件中實際實現會導致一些令人頭疼的問題在編譯時(不是在鏈接...我甚至沒有達到這一點)。 為什么? 好吧,我不會詳細說明,但編譯器顯然試圖解決其他頭文件等中可能定義的所有函數,迫使可憐的開發人員開始引入各種頭文件等。

是不是總是最好保持頭文件沒有任何實現,只是將它們用於'聲明'? 這樣可以更容易地將它們包含在多個項目中,而不必攜帶大量額外的垃圾。

你對此有何看法?

保持標頭不受實現的影響,除非您希望實現內聯(例如,瑣碎的getter / setter)。 當然,除非他們是模板。

我認為沒有理由為構造函數做一個例外。 將它們放在.cpp文件中。

需要注意的一點是,如果在頭文件中定義了成員函數,它必須位於類體內,或者必須明確標記為inline 換句話說,在頭文件中執行此操作是完全錯誤的:

class A {
  public:
    A();
};

A::A() {
  // constructor body
}

這是錯誤的原因是因為它會使編譯器在每個編譯單元中包含定義,而顯然任何函數只能定義一次。 以下是做同樣事情的正確方法:

class A {
  public:
    inline A();
};

inline A::A() {
  // constructor body
}

要么:

class A {
  public:
    inline A() { // inline isn't required here, but it's a good style
     // constructor body
    }
};

在這兩種情況下,構造函數都是內聯的。 使其成為常規外聯函數的唯一正確方法是在實現文件中定義它,而不是在頭文件中定義它。 這是這兩種方法之間最重要的區別。

現在,值得注意的是內聯是一種優化。 並且一如既往地進行優化,最好避免它們,直到證明有必要。 在內聯可能導致的其他問題中,存在兼容性問題:如果更改未內聯的函數的主體,則只需重新編譯定義它的單元,並且每個人都立即開始使用新實現。 使用內聯函數,您需要重新編譯包含相關標題的每個單元,這可能很麻煩,尤其是如果標題由不同的人在不同的項目中使用。

換句話說,盡可能使用常規的外部定義,直到通過分析特定函數調用是性能瓶頸來證明它為止。 這個規則的唯一合理的例外是微不足道的setter和getter,即使使用它們也最好小心 - 有一天它們可能變得非常重要,這將意味着大量的重新編譯和兼容性破壞。

需要考慮的另一個注意事項:對頭文件的任何更改都需要重建包含該頭文件的所有文件。 大多數構建系統將重建依賴於修改的頭文件的源(* .cpp / .cc)文件。

如果更改頭文件中定義的類的方法,則將重建包括頭文件的所有源文件。 如果更改源文件中的方法,則僅重建源文件。 這可能是中型到大型項目的問題。

為簡化構建過程,應在源文件中定義類的大多數方法。 應在頭文件中定義用於內聯的小方法和其他候選項。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM