當寫簡單程序時候,所有東西可以放在一個文件中,但程序較大時,這樣做並不明智。前面我們討論過如何將程序分割,即應該成對的構建程序文件。對每個函數定義文件(definition),應該有相應的函數聲明頭文件(declaration). 對類,我們有類似的原則。即應該成對的創建文件,一個頭文件和一個定義文件。類的定義被放在頭文件中,相應的定義文件放置成員函數的定義,只有內聯函數的實現纔可以放在頭文件中,其它成員函數的實現應該放在另外一個單獨的cpp文件之中。如果我們有一組類,他們彼此相似,那我們可以將幾個類的定義放在同一個頭文件中。此時,定義文件應該包含所有類的成員函數的定義。
class MyClass // class declaration
暗示名字MyClass定義了一個類,他的完整定義將稍後出現。
看一個例子:類Flight, 描述一般航班。頭文件名字flight.h,包含了類Flight的定義。文件看起來如下:
//The file flight.h
#ifndef FLIGHT_H
#define FLIGHT_H
#include "clock.h"
#include <string>
using namespace std;
class Flight{
public:
void init(string flight_no,
int dep_h,int dep_m,int arr_h,int arr_m);
void info();
void delay(int min);
private:
string no;
Clock dep,arr;
};
#endif
c++中,一個類不能定義多餘一次。上術代碼第2,3和最後一行用來防止flight.h在編譯過程中被包含多餘一次。FLIGHT_H是一個宏的名字,是一個我們自己定義的常數。第二行檢查是否這個名字的宏被定義過(#ifndef means if not defined)。 如果沒有定義,編譯器將讀取整個頭文件,直到#endif。因此,此流程確保頭文件不會被定義多於一次。因此,對所有包含類的定義的頭文件都應採用此步驟。建議宏和頭文件有相同的名字,但全部採用大寫。
此類有三個數據成員:字符數組no,包含航班號,兩個clocks,名字是dep和arr,暗示離開和達到時間。我們假設類Clock是在一個頭文件爲clock.h中定義,因此必須在程序中包含此頭文件(第4行)。
Flight有三個成員函數,init用來初始化航班,航班號,離開和到達時間,info輸出關於航班的信息。delay被調用當航班延誤。延遲時間作爲輸入參數。函數delay將更新此航班離開和達到時間。
就函數而言,頭文件不應該包含函數體的定義,僅僅是函數的聲明。此原則對類同樣適用。因此我們將成員函數的定義放在相應的定義文件“flight.cpp”中。
//the file flight.cpp
#include "flight.h"
#include <iostream>
#include<iomanip>
#include<string>
using namespace std;
void Flight::init(string flight_no,
int dep_h,int dep_m,int arr_h,int arr_m)
{
no = flight_no;
dep.set(dep_h, dep_m, 0);
arr.set(arr_h, arr_m, 0);
}
void Flight::info()
{
cout << "Flight no " << no;
cout << ", Dep "; dep.write(false);
cout << ", Arr ", arr.write(false);
cout << endl;
}
void Flight::delay(int min)
{
for (int i = 1; i < min * 60; i++)
dep.tick();
for (int j = 1; j <= min * 60; j++)
arr.tick();
}
爲了使程序知道類的定義,flight.h必須要被包括,clock.h則不需要,因爲他已經被包括在flight.h之中了。 數據成員dep和arr是類Clock的對象,Clock的成員函數用來處理這些對象。數據成員dep和arr不能直接訪問,因爲他們依賴類Clock的私有部分。
使用類Flight的程序必須包含flight.h。舉例如下:
//the file main.cpp
#include "flight.h"
void main()
{
Flight f;
f.init("SK1853", 8, 10, 10, 55);
f.delay(15);
f.info();
system("pause");
}
頭文件不應該包含成員函數的單獨定義,一個重要例外是inline函數,它必須在頭文件中定義!!!
如clock.h可以看起來如下:
class Clock {
public:
void set(int hour, int min, int sec);
int read_hour() { return h; }
int read_min() { return m; }
int read_sec() { return s; }
void write(bool write_sec = true);
void tick();
private:
int h, m, s;
};
inline void Clock::set(int hour,int min,int sec)
{
h=hour;m=min;s=sec;
}
此處我們讓函數read_hour,read_min,read_sec和set作爲inline函數。 注意,如果函數set沒有被定義爲inline函數,它必須放在一個單獨的文件clock.cpp之中!!!
綜上,clock.h可以寫成下面的樣子:
class Clock {
public:
void set(int hour, int min, int sec);
int read_hour() { return h; }
int read_min() { return m; }
int read_sec() { return s; }
void write(bool write_sec = true);
void tick();
private:
int h, m, s;
};
由於我們沒有將set, write,tick函數定義爲inline函數,因此我們需要一個單獨的cpp文件來實現這些函數,clock.cpp文件如下:
#include "clock.h"
#include<iomanip>
#include <iostream>
using namespace std;
void Clock::set(int hour, int min, int sec)
{
h = hour; m = min; s = sec;
}
void Clock::write(bool write_sec)
{
std::cout << setw(2) << setfill('0') << h
<< ':' << setw(2) << setfill('0') << m;
if (write_sec)
std::cout << ':' << setw(2) << setfill('0') << s;
}
void Clock::tick()
{
s = (s + 1) % 60;
if (s == 0)
{
m = (m + 1) % 60;
if (m == 0)
h = (h + 1) % 24;
}
}
此cpp文件中包含了clock.h中定義的另外三個非inline函數的實現。將flight.h,clock.h,flight.cpp,clock.cpp和main.cpp一起編譯即可。