2010-08-26 103 views
5

我有一個理論問題而不是錯誤報告。對C++頭文件的基本理解

我是一個菜鳥的C++程序員,努力促進該走

使用VC++編譯器VS2008

我經常發現自己想知道爲什麼我想在頭文件中的一些動作。

例如看看這個代碼塊:

#include "DrawScene.h" 
#include "Camera.h" 
#include "Player.h" 
#include "Grid.h" 
#include "InputHandler.h" 
#include "GameState.h" 

class Controller 
{ 
public: 
private: 
public: 
Controller(); 
~Controller(){} 
void Update(); 

private: 
}; 

而且迷上了CPP文件,controller.cpp隨之

#include "stdafx.h" 
#include "glut.h" 
#include "Controller.h" 
#include <iostream> 

Grid* grid_ptr = new Grid(); 
InputHandler* inputHandler_ptr = new InputHandler(); 
DrawScene* drawScene_ptr = new DrawScene(); 
GameState* gameState_ptr = new GameState(); 

Controller::Controller() 
{ 

} 

void Controller::Update() 
{ 

} 

是什麼來決定,其中包括去哪裏的好方法?到目前爲止,我一直在用「無論什麼作品」的方法,但我覺得它有點不專業。

現在即使您可以說我的代碼有X語法錯誤和設計缺陷,但請注意,但我希望信息保留在使用.h VS .cpp文件中。

爲什麼還會有這樣的設計?當製作任何一種基於OOP的C++程序時,什麼是凹坑和陷阱總是會輕微踩踏?

是什麼引發了這個問題,我順便說一句,我想通知讀者的頭文件將有存儲在控制器中的對象,但分配這些未初始化的對象似乎是不可能的,而不使它們成爲靜態的。

注意:我出自C# - > C++,可能有助於瞭解。這是我對代碼的看法。

預先感謝您的努力!

編輯:26/08/2010 18:16

所以建造時間是好包括精髓。還有更多要謹慎嗎?

+0

我自己一個月的時間採取單獨的編譯,在5分鐘內告訴:http:// stackoverflow。com/questions/2037880/how-can-i-avoid-including-class-implementation-files/2038233#2038233 – 2010-10-20 18:12:11

+0

不必擔心編譯時間成爲問題,直到他們*出現問題:我將把* *在標題中開始,稍後再移動。 – 2010-10-20 18:15:16

回答

4

一般來說,標題應該駐留在cpp文件中。對於包含標準庫(可能包含第三個庫),您可以將它們粘貼到標題中。然而,專門爲你的項目定義的頭文件應儘可能在cpp文件中。

原因是編譯時間和依賴性問題。每次更改頭文件時,編譯器都必須重新編譯包含它的每個源文件。當在另一個頭文件中包含一個頭文件時,編譯器必須重新編譯每個包含頭文件的cpp文件。

這就是爲什麼前向聲明和PIMPL(指向IMPLEMENT或不透明指針)模式很流行。它允許您將至少一些更改/實現移出頭文件。例如:

// header file: 
class SomeType; 

class AnotherType 
{ 
private: 
    SomeType *m_pimpl; 
}; 

不需要你有 「sometype.h」,而:

// header file 
class AnotherType 
{ 
private: 
    SomeType m_impl; 
}; 

一樣。編輯:其實,如果您總是在包含「anothertype.h」的每個cpp文件中的「anothertype.h」之前包含「sometype.h」,則不需要在「anothertype.h」中包含「sometype.h」。

有時可能很難將頭文件移動到cpp文件。在這一點上,你有一個決定 - 是否更好地通過抽象代碼的努力,所以你可以這樣做,還是更好地添加包含?

+0

感謝您將實現指針引入我的注意力中,我不得不多次閱讀它,但我認爲我明白了,即使我很可能需要再閱讀一些內容。 猜猜它會隨着經驗而增長,只是嘗試和學習。 謝謝! – Proclyon 2010-08-26 16:10:38

4

如果絕對必要,請僅在其他標頭中包含標題。如果標題可以單獨在源文件中,那麼這是最好的地方。如果您只使用指針和對它們的引用,則可以在頭中使用類的前向聲明。您的DrawScene,GameState,GridInputHandler類似乎可能屬於此類別。

請注意,C++作爲一種語言並不關心標題和源文件之間的區別。這只是開發人員用來維護代碼的一個非常常見的系統。使用頭文件的明顯優勢是避免代碼重複,並且在某種程度上有助於對類,模板和內聯函數實施單一定義規則。

+0

所以這就是它的一般功能,然後.h和.cpp,很有趣!謝謝 – Proclyon 2010-08-26 15:54:04

15

這是我的個人意見,而不是一個共識的最佳實踐,但我的建議是:在頭文件中,只包括那些有必要使頭文件的內容編譯沒有語法錯誤頭。如果你可以使用前向聲明而不是嵌套包含,那就這樣做。

原因是,在C++中(不像C#,iiuc)沒有導出控制。標題中包含的所有內容都會顯示在頭部中,這可能是您界面的用戶看不到的大量垃圾。

+1

不僅如此,每次將頭文件包含在其他任何源文件中時,編譯器都需要編譯頭文件的內容以及所有內容,從而縮短編譯時間。所以保持它們儘可能小是始終有利的。 – Praetorian 2010-08-26 15:41:56

+0

如果您可以使用正向聲明而不是嵌套包含,請這樣做。 對不起,什麼?請你爲我詳細說明這個部分嗎? – Proclyon 2010-08-26 15:48:12

+0

我認爲Zack的意思是,只有當文件不需要知道任何關於你正在聲明的類的聲明時,前向聲明才起作用。通常這意味着該文件只有指向該類型的指針,並且從不去引用它們。 – 2010-08-26 17:08:25

2

頭文件包含函數,類和其他對象的聲明,而cpp文件是爲了實現這些先前聲明的對象。

頭文件主要出於歷史原因而存在。如果在你實際調用它們之前給出了代碼使用的所有函數,類等的定義,那麼構建一個C++編譯器會更容易。

通常你使用cpp作爲你的實現。在頭文件中實現函數會自動將它們內聯,因此除非這些函數非常小和/或被頻繁調用,否則這通常不是您想要的。

+0

那麼如果我的編譯器由於#include在cpp文件中而不知道該對象是什麼類型,那麼我怎麼可能用一個前向聲明在頭文件中聲明一個對象呢?對我來說,這聽起來像能夠解釋一個天生的男人是什麼顏色的藍色。 – Proclyon 2010-08-26 16:14:10

+1

通過向前聲明一個類型,你只需告訴你的編譯器存在某種類型。不是類型做什麼或它如何做。你的比喻有點錯誤,因爲盲人根本沒有顏色的概念,而編譯器確實知道什麼類型。 – 2010-08-26 18:38:17

+0

它有點像IDL/WSDL/etc文件 - 頭文件是'契約',顯示你可以訪問的東西,cpp包含你隱藏的實現。我認爲這是一件好事。 – gbjbaanb 2010-10-20 18:35:53

3

避免在您的.h文件中放太多(讀取,任何不必要的)#includes。這樣做會導致構建時間長,例如每當你改變Camera.h你將會改變Controller.h,所以包含Controller.h的任何東西都需要被重建。即使它只是一個已經改變的評論。

如果只存儲指針成員,則使用前向聲明,然後將#includes添加到cpp文件中。

理論上,.h文件只包含接口和.cpp文件的實現。但是,由於私人成員可以說是實施,而不是界面,所以這不是嚴格正確的,因此需要進行前瞻性聲明以儘量減少不必要的重建。

在C++中,可能會將整個實現內聯地包含在類定義文件中,就像使用Java一樣,但這確實會打破.h/.cpp接口/實現規則。

+0

非常有用的信息,謝謝! – Proclyon 2010-08-26 15:55:52