在设计一个类的时候,通常是将类的定义及类成员函数的声明放到头文件(即.h文件)中,将类中成员函数的实现放到源文件(即.cpp)中。对于animal类需要animal.h和animal.cpp两个文件,对于fish类需要fish.h和fish.cpp。对于main()函数,我们把它单独放在EX10.cpp文件中。
animal.h
class animal
{
public:
animal();
~animal();
void eat();
void sleep();
virtual void breathe();
};
animal.cpp
#include"animal.h"
#include<iostream.h>//<>和""表示编译器在收索头文件时的顺序不同,<>表示从系统目录下开始搜索,然后在搜索PATH环境变量所列出的目录,不搜索当前目录;""表示从当前目录开始搜索,然后是系统目录和PATH环境变量所列出的目录。如果知道头文件在系统目录,使用<>会比较快。
animal::animal()//::叫做作用于标识符,用于指明一个函数属于哪个类或一个数据成员属于哪个类。::如果前面不跟类名,表示是全局函数(即非成员函数)或全局数据。
{
}
animal::~animal()
{
}
void animal::eat()//虽然在函数体中什么也没写,但是仍然实现了这个函数
{
}
void animal::sleep()
{
}
void animal::breathe()//注意,在头文件(.h文件)中加了virtual后,在源文件(.cpp文件)中就不用加virtual了。
{
cout<<"animal breathe"<<endl;
}
fish.h
#include"animal.h"//因为fish类是从animal类继承来的,要让编译器知道animal是一种类的类型,就要包含animal.h头文件
class fish:public animal
{
public:
void breathe();
};
fish.cpp
#include"fish.h"
#include<iostream.h>
void fish::breathe()
{
cout<<"fish bubble"<<endl;
}
EX10.cpp
#include"animal.h"
#include"fish.h"
void fn(animal *pAn)
{
pAn->breathe();
}
void main()
{
animal *pAn;
fish fh;
pAn=&fh;
fn(pAn);
}
但是这样编译会发现类重复定义的错误,因为EX10.cpp包含了animal.h和fish.h两个头文件,编译器展开animal.h头文件时,知道animal这个类的定义了,接着展开fish.h头文件,而fish.h头文件中包含animal.h,再次展开animal.h,于是重复定义。
要解决头文件重复包含问题,可以私用条件预处理指令,修改后的头文件如下所示。
animal.h
#ifndef ANIMAL//我们一般用#define定义一个宏,但是在这里只是为了判断ANIMAL是否定义,以此来避免重复定义。
#define ANIMAL
class animal
{
public:
animal();
~animal();
void eat();
void sleep();
virtual void breathe();
};
#endif
fish.h
#include"animal.h"
#ifndef FISH
#define FISH
class fish:public animal
{
public:
void breathe();
};
#endif
这样,当编译器展开animal.h头文件时,头肩预处理指令判断ANIMAL没有定义,于是定义它,然后继续执行,定义animal这个类,接着展开fish.h头文件,fish.h头文件中包含animal.h,再次展开animal.h 这时条件预处理指令发现ANIMAL已经定义,于是跳转到#endif,执行结束。
于是animal这个类只定义了一次。