C++中前置聲明和頭文件包含

假設有一個Date類

Date.h

  1. class Date {  
  2. private:  
  3.     int year, month, day;  
  4. };  

如果有個Task類的定義要用到Date類,有兩種寫法

其一

Task1.h

  1. class Date;  
  2. class Task1 {  
  3. public:  
  4.     Date getData();  
  5. };  

其二

Task2.h

  1. #include "Date.h"  
  2. class Task2 {  
  3. public:  
  4.     Date getData();  
  5. };  

一個採用前置聲明,一個採用#include<Date.h>加入了Date的定義。兩種方法都能通過編譯。但是 Task1.h 這種寫法更好。如果Date.h 的 private 成員變量改變,比如變成 double year, month, day; ,Task1.h 不需要重新編譯,而 Task2.h 就要重新編譯,更糟的是如果 Task2.h 還與其他很多頭文件有依賴關係,就會引發一連串的重新編譯,花費極大的時間。可是事實上改變一下寫法就可以省去很多功夫。所以能用前置聲明代替#include 的時候,儘量用前置聲明


有些情況不能用前置聲明代替#include

比如Task1.h改成

  1. class Date;  
  2. class Task1 {  
  3. public:  
  4.     Date d;  
  5. };  

會編譯錯誤,因爲Date d定義了一個Date類型變量,編譯器爲d分配內存空間的時候必須知道d的大小,必須包含定義Date類的Date.h文件

這是可以採用指針來代替

  1. class Date;  
  2. class Task1 {  
  3. public:  
  4.     Date *d;  
  5. };  

指針的大小是固定的。在32位機上是4字節,64位機上是8字節。這時編譯Task1的時候不需要Date的大小,所以和Date的定義無關。

上述例子可以說明

如果使用object reference 或 object point 可以完成任務,就不要用object

這樣可以盡最大可能避免#include

爲聲明式和定義是提供不同的頭文件 

在函數庫的設計過程中,接口的設計就要遵循上述準則。

一個接口的頭文件是這樣的

interface.h

  1. class Date;  
  2. class Address;  
  3. class Email;  
  4. Date getDate();  

如果客戶只用到Date類,編譯器就只會去編譯Date.h,而不去編譯Address.h,Email.h 等等文件。


究竟什麼時候需要前置聲明,什麼時候需要頭文件包含呢?

      頭文件包含其實是一想很煩瑣的工作,不但我們看着累,編譯器編譯的時候也很累,再加上頭文件中常常出現的宏定義。感覺各種宏定義的展開是非常耗時間的,遠不如自定義函數來得速度。我僅就不同頭文件、源文件間的句則結構問題提出兩點原則,僅供參考:

  第一個原則應該是,如果可以不包含頭文件,那就不要包含了。這時候前置聲明可以解決問題。如果使用的僅僅是一個類的指針,沒有使用這個類的具體對象(非指針),也沒有訪問到類的具體成員,那麼前置聲明就可以了。因爲指針這一數據類型的大小是特定的,編譯器可以獲知。

  第二個原則應該是,儘量在CPP文件中包含頭文件,而非在頭文件中假設類A的一個成員是是一個指向類B的指針,在類A的頭文件中使用了類B的前置聲明並編譯成功,那麼在A的實現中我們需要訪問B的具體成員,因此需要包含頭文件,那麼我們應該在類A的實現部分(CPP文件)包含類B的頭文件而非在聲明部分(H文件)包含。


發佈了63 篇原創文章 · 獲贊 13 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章