C++中的C++頭文件是用戶應用程序和函數庫之間的橋梁和紐帶,在整個軟件中,頭文件不是最重要的部分,但它是C++語言家族中不可缺少的組成部分,有了它給技術人員提供了大大的便捷。
因為一個頭文件的內容實際上是會被引 入到多個不同的.cpp文件中的,並且它們都會被編譯。放聲明當然沒事,如果放了定義,那麼也就相當於在多個文件中出現了對於一個符號變量或函數)的定 義,縱然這些定義都是相同的,但對於編譯器來說,這樣做不合法。
所以,應該記住的一點就是,.h頭文件中,只能存在變量或者函數的聲明, 而不要放定義。即,只能在C++頭文件中寫形如:extern int a;和void f();的句子。這些才是聲明。如果寫上int a;或者void f() {}這樣的句子,那麼一旦這個頭文件被兩個或兩個以上的.cpp文件包含的話,編譯器會立馬報錯。關於extern,前面有討論過,這裡不再討論定義跟 聲明的區別了。)
但是,這個規則是有三個例外的。
一,頭文件中可以寫const對象的定義。因為全局的const對象默 認是沒有extern的聲明的,所以它只在當前文件中有效。把這樣的對象寫進頭文件中,即使它被包含到其他多個.cpp文件中,這個對象也都只在包含它的 那個文件中有效,對其他文件來說是不可見的,所以便不會導致多重定義。同時,因為這些.cpp文件中的該對象都是從一個頭文件中包含進去的,這樣也就保證 了這些.cpp文件中的這個const對象的值是相同的,可謂一舉兩得。同理,static對象的定義也可以放進C++頭文件。
二,C++頭文件中可 以寫內聯函數inline)的定義。因為inline函數是需要編譯器在遇到它的地方根據它的定義把它內聯展開的,而並非是普通函數那樣可以先聲明再鏈 接的內聯函數不會鏈接),所以編譯器就需要在編譯時看到內聯函數的完整定義才行。
如果內聯函數像普通函數一樣只能定義一次的話,這事兒就難辦了。因為在 一個文件中還好,我可以把內聯函數的定義寫在最開始,這樣可以保證後面使用的時候都可以見到定義;但是,如果我在其他的文件中還使用到了這個函數那怎麼辦呢?
這幾乎沒什麼太好的解決辦法,因此C++規定,內聯函數可以在程序中定義多次,只要內聯函數在一個.cpp文件中只出現一次,並且在所有的.cpp文 件中,這個內聯函數的定義是一樣的,就能通過編譯。那麼顯然,把內聯函數的定義放進一個頭文件中是非常明智的做法。
三,頭文件中可以寫類 class)的定義。因為在程序中創建一個類的對象時,編譯器只有在這個類的定義完全可見的情況下,才能知道這個類的對象應該如何布局,所以,關於類的 定義的要求,跟內聯函數是基本一樣的。
所以把類的定義放進C++頭文件,在使用到這個類的.cpp文件中去包含這個C++頭文件,是一個很好的做法。在這裡,值得一提 的是,類的定義中包含著數據成員和函數成員。
數據成員是要等到具體的對象被創建時才會被定義分配空間),但函數成員卻是需要在一開始就被定義的,這也就 是我們通常所說的類的實現。一般,我們的做法是,把類的定義放在頭文件中,而把函數成員的實現代碼放在一個.cpp文件中。這是可以的,也是很好的辦法。
不過,還有另一種辦法。那就是直接把函數成員的實現代碼也寫進類定義裡面。在C++的類中,如果函數成員在類的定義體中被定義,那麼編譯器會視這個函數為 內聯的。因此,把函數成員的定義寫進類定義體,一起放進頭文件中,是合法的。
注意一下,如果把函數成員的定義寫在類定義的C++頭文件中,而沒有寫進類定義中, 這是不合法的,因為這個函數成員此時就不是內聯的了。一旦頭文件被兩個或兩個以上的.cpp文件包含,這個函數成員就被重定義了。