2010-12-08 32 views
3

我已經看到放置在單獨的C++中的類的代碼,而方法定義放置在頭文件中。我的第一個OOP經驗是Java,所有的方法都放在類文件中,而我更喜歡這個。在.h和.cpp文件中放置方法

將我的所有方法放在頭文件中是否會影響編譯器生成的彙編代碼?

如果是這樣,將類的整個代碼放在它的頭文件中對性能有害嗎?

回答

2

有是爲頭/實施拆分和 分別編譯幾個正當的理由:
1,這可能是一個工作要求 - 例如,你提供一個 二進制庫+標題給別人,或者你同事們太保守 接受別的。
2.它仍然需要開發非常大的項目(例如,> 10M的源代碼), ,因爲在每次修改後重建整個應用程序將變得很痛苦。 (但編譯jpeglib或zlib作爲單個模塊應該還是可以的)
3.有一種觀點認爲它更容易使用頭文件作爲參考,查看 的功能等。 (但通常最好寫一個適當的文檔;不像頭文件,文檔中的錯誤不太可能影響你的程序)

此外,還有更多的理由不再使用它:
1.你會喜歡避免維護重複的代碼。
2.類方法不需要前向聲明
3.模板只能在頭文件中聲明
4。不需要函數內聯的情況實際上相當罕見, 即在緊密循環中多次調用大函數,但有noinline attibutes和PGO。否則內聯可以提高速度。對於代碼膨脹,大多數庫已經很龐大了。
5.總體而言,作爲單一來源編譯的程序速度越來越快,因爲編譯器可以做得更好,所以 。
6.如果沒有頭文件,源代碼會經常大約減少兩倍,編譯器將能夠正確地檢查語法,因此您不能將 意外地將extern「C」cdecl函數原型鏈接到變量作爲實施。另外總體而言,它會更具可移植性,因爲不同的鏈接器對名稱匹配有不同的想法。
7.其奇怪但動態的分配經常僅用於 頭文件樣式 - 通過在單個類中定義所有的 細節可自動解決依賴關係,但人們更喜歡使用指向部分類聲明的指針(而後追捕內存泄漏)。

現在,對於單獨的對象模塊的幾個積分:是每個對象模塊,它似乎是「基準」的幾個不同的操作與一個單獨的可執行的模式的唯一方式生成的gcc
4. PGO統計信息。
5.它有可能編譯不同的模塊與不同的編譯器選項進行速度優化。還有一些編譯器擴展,但它們不是很可靠。
6.有時編輯器可以在修改某些內容時爲代碼的另一部分做些奇怪的事情 - 但通常它不能傳播到對象模塊之外。

6

問題是複雜的C++程序是通過編譯多個對象,然後將它們鏈接在一起而創建的。每個對象通常來自編譯一個實現文件(例如「.cpp」,「.cc」等),其可以直接和間接地包括很多頭文件。因此,如果您編寫了一個好的類並將代碼放入標題中,那麼該代碼可以包含在多個對象文件中,然後編譯器會冗餘地生成它,並且進一步 - 鏈接器不會(並且不能輕鬆地)比較版本以查看它們是否相同並刪除冗餘副本(如果使用相對地址 - 「位置獨立代碼」更容易 - 但這是另一個故事)。另請參閱下面的jalf評論。

所以,你不想在你的頭文件中使用不同的線外功能。如果它們名義上是inline函數 - 由於使用inline關鍵字或者在類中定義了 - 那麼編譯器將不得不承擔額外的工作,並確保它們的任何非線性版本在可執行文件。但是,對於非線性函數來說,程序員仍然承擔着這樣的負擔。此外,如果您在頭文件中提供了實現,則會爲每個對象冗餘編譯,並且對頭的任何更改都會強制重新編譯所有依賴對象。單獨對象中的外聯函數可以被改變,單個對象被重新編譯,然後它可以與其他預先存在的對象鏈接以形成新的可執行文件。在大型項目中,這節省了大量的編譯時間。

+1

+1我真的很喜歡你的答案。但出於好奇,你對模板有什麼想法?我見過很多模板代碼,包括額外的「內聯」頭文件或是一大堆方法。 – GWW 2010-12-08 06:01:28

+1

@GWW:爲每種類型的組合實例化模板,這使得它們非常快速且功能強大,但高度依賴於客戶端代碼。在整個C++歷史中,沒有人找到避免需要通過頭部公開「實現」的好方法。 #包含另一個文件有時可能有助於保持API的獨立性,就像在類/結構聲明之後放置函數定義一樣,但最佳結果會隨許多因素而變化(函數長度,文檔數量和樣式,複雜性等,數字/技能的客戶用戶與實施維護者)。它*是*凌亂:-) – 2010-12-08 07:56:26

1

是的,位於標題中的方法是內聯的,所以它們通常更快(尤其是短的)。

主要缺點是每個標頭的修改都會導致包含它的每個文件的重新編譯。