使用頭文件
在創建了頭文件之後,只要把它的文件名用雙引號括起來寫在如下所示的指令裏就可以導入它:
#include “fishc.h”
如果沒有給出路徑名,編譯器將到當前子目錄以及當前開發環境中的其他邏輯子目錄裏去尋找頭文件。
爲了消除這種猜測,在導入自己的頭文件時可以使用相對路徑。如果頭文件與主程序文件在同一個子目錄裏,則可以這麼寫:
#include “./fishc.h”
如果頭文件位於某個下級子目錄裏,那麼以下級子目錄的名字開頭:
#include “includes/fishc.h”
最後,如果頭文件位於某個與當前子目錄平行的”兄弟”子目錄裏,則需要這麼寫:
#include “../includes/fishc.h”
請務必注意,Windows通常使用反斜槓作爲路徑名裏的分隔符。
請看演示:Example (源代碼下載)
創建實現文件
回到Rational這個栗子,我們帶大家來進一步實現模塊化編程。
rational.h頭文件包含Rational類的聲明,但不包含這個類的實現代碼。
這種分割可能剛開始接觸的朋友覺得有點奇怪,但在實踐中非常普遍。
因爲把接口(函數的原型)和實現(函數體的定義)分開是對代碼進行模塊化的基本原則之一。
頭文件的重要性不僅體現在它們可以告訴編譯器某個類、結構或函數將有着怎樣的行爲,還體現在它們可以把這些消息告訴給程序員。
作爲苦逼程序猿一枚,你只需看到函數的聲明就可以瞭解到你需要知道的一切:函數的名字,它的返回值類型和它的輸入參數的類型和數量。
知道了這些東西,你就可以使用那個函數了,而根本用不着關心它到底是如何工作的。
編譯器就不同了,它必須讀取某個類或函數的實現代碼。
作爲一個通用原則,應該把聲明放在一個頭文件裏,把實現代碼放在一個.cpp文件裏。
現在我們就演示下rational這個程序如何分開和拼湊成一個完整的程序。
C預處理器
剛纔的示例程序還有一個小小的問題需要解決,就是rationcal.cpp和main.cpp文件都包含了rational.h頭文件。
這意味着rational.h類被聲明瞭兩次,這顯然沒有必要(如果它是一個結構,聲明兩次還將導致編譯器報錯呢~)
解決方案之一是把其中一個文件裏的#include刪掉即可。這固然很容易可以解決的問題,但卻會給今後留下麻煩。。。。。。
當然我們在這裏提出是因爲有更好的解決方案!
利用C++預處理器,我們可以讓頭文件只在這個類還沒有被聲明過的情況下才聲明它。
以前的課程中,我們曾建議大家註釋很多段代碼的話用預處理的方式,比起/* */要效果好:
#if 0
// 這裏有代碼
// 這裏有好多代碼
// 這裏有好多好多代碼
// 這裏有好多好多好多代碼
#endif
#ifndef LOVE_FISHC
#define LOVE_FISHC
#endif
這看起來好像沒什麼用,但事實卻並非如此。這段代碼的含義是:如果LOVE_FISHC還沒有定義則定義之,看出這有什麼作用了嗎?
#ifndef LOVE_FISHC
#define LOVE_FISHC
class Rational{ … };
#endif
如果LOVE_FISHC還沒有定義,這裏將發生兩件事兒:定義一次LOVE_FISHC,然後對Rational類做出聲明等操作。
這樣一來,即使包含着這段代碼的文件在某個項目裏被導入了100次,Rational類也只會被聲明一次,因爲在第一次之後LOVE_FISHC就有定義!
作爲一種固定模式,這裏使用的常量名通常與相應的文件名保持一致,把句點替換爲下劃線。
於是,rational.h文件將對應RATIONAL_H