当写简单程序时候,所有东西可以放在一个文件中,但程序较大时,这样做并不明智。前面我们讨论过如何将程序分割,即应该成对的构建程序文件。对每个函数定义文件(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一起编译即可。