2011-06-03 34 views
7

所以有一天,我正在瀏覽一些舊的C++書籍,並注意到創建一個我從未見過的C++類的方法。到目前爲止,我所見過的所有東西都使用#include「header.h」,並分別編譯實現文件。我看到這本書的作者所做的實際上是在頭文件末尾的實現中加入一個包含指令,並從編譯中省略.cpp文件。有人使用過這種風格嗎?C++ #include風格差異

例如: 我 的main.cpp employee.h employee.cpp

//main.cpp 
#include <iostream> 
#include <stdio.h> 
#include <string> 
#include "employee.h" 
void main() 
{/*some code*/} 

//employee.h 
#ifndef EMPLOYEE_H 
#define EMPLOYEE_H 
class employee 
{ 
    public: 
    //public members 
    private: 
    //private members 
} 
#endif 

//employee.cpp 
#include "employee.h" 
#include <string> 
//public member definitions 

我會normaly編譯這個項目像這樣:

g++ main.cpp employee.cpp 

但在筆者的例子是這樣的

//main.cpp 
#include <iostream> 
#include <stdio.h> 
#include <string> 
#include "employee.h" 
void main() 
{/*some code*/} 

//employee.h 
#ifndef EMPLOYEE_H 
#define EMPLOYEE_H 
class employee 
{ 
    public: 
    //public members 
    private: 
    //private members 
} 
#include "employee.cpp" // <-- the line of code that caught my attention 
#endif 

//employee.cpp 
#include <string> 
//public member definitions 

而產生的代碼編譯爲

g++ main.cpp 

這僅僅是一種風格偏好還是有這個任何真正的實惠?我認爲它不會很好地擴展,但我不是一個超級熟練的C++程序員。

+3

這是哪本書? – 2011-06-03 16:24:45

+4

是的,我也想避免那本書。 – Beta 2011-06-03 16:27:14

+0

@Neil「C++類和數據結構」Jeffrey S. Childs ISBN 0-13-158051-5 978-0-13-1558051-0。其實它並沒有那麼古老,這本書擁有2008 – 2011-06-03 16:27:57

回答

3

這樣做會帶來類的定義,每一個翻譯單元,其中頭文件包括在內。這是一個非常不尋常的範例,可能會危害您的編碼健康。特別是,如果你有main.cppfoo.cpp這兩者都是#include "employee.h",那麼employee上的所有方法都會被定義兩次,這是違反了One Definition Rule並且會產生連接錯誤。爲了解決這些鏈接器錯誤,你需要將定義移動到他們自己的翻譯單元,或者將它們標記爲inline(這可能會也可能不起作用)。

然而這在某些情況下是有用的習慣用法。特別是使用必須在翻譯單元內定義的模板。在這種情況下,如果您希望在單獨的文件中進行聲明和實現以提高可讀性,則可以執行文件結尾#include。當我這樣做時,我使用了一個特殊的文件擴展名.hpp來表示該文件是特殊的,因爲它並不打算自行編譯。一個例子見this answer

+1

@Richard:ODR也是關於單獨翻譯單元中的多個定義,並且包括警衛不會阻止這種情況發生。如果標題包含非內聯函數定義並且它包含在多個翻譯單元中,那麼您將收到鏈接錯誤。 @John:聲明函數'inline' *將*修正鏈接器錯誤 - 這正是'inline'的用途。 – 2011-06-03 21:43:14

+0

@Mike:Doh - 腦凍結....當然你是對的! - 我刪除了令人尷尬的評論! – 2011-06-08 12:51:18

2

這可能不是主流的書。無論如何,如果我們通過「編譯」的條件來定義正確性,那麼是的,這是一個風格問題,兩種風格都是正確的。

但是,根據與其他編程語言相匹配的標準和設計準則,唯一真正正確的樣式是第一個,它符合單獨編譯翻譯單元的精神。正如你自己所說的,第二種風格不會很好地擴展。

還有一點是注意#include < stdio.h中>,這不是標準的任何更多:

#include <cstdio> 
2

這肯定會工作,但它有兩個缺點:

  • 編譯時間越來越長 - 通常,如果你改變一個文件,你只需要編寫一個文件,鏈接器將其與結合其他較舊的編譯結果。當所有內容都包含在單個文件中時,所有內容都需要立即重新編譯。
  • 潛在的命名空間衝突 - 在一個模塊中聲明的任何符號現在都可以看到它們。如果您使用任何宏,這可能是一個大問題。
3

該方法有時在提供模板時使用,等同於在頭文件中提供模板和實現,但是允許人們在不通過代碼的情況下讀取模板聲明。等價地,如果您提供了d函數,如果您也這樣做了,這將是可以理解的(不會達到建議的程度,但可以理解)。

對於其他任何東西,這是一個壞方法。它不僅要求所有翻譯單元實際編譯所有函數定義,還需要聲明所有函數爲inline,或者包含來自單個翻譯的標題,否則會觸發鏈接器錯誤。

0

這實際上是我在構建系統中看到的一個技巧,每晚構建系統以加速它們,包括所有cpp文件,並且它們編譯時可以在總體速度上產生一些重大收益。