头文件(.h):
写类的声明(包括类里面的成员和方法的声明)、函数原型、#define常数等,但一般来说不写出具体的实现。
在写头文件时需要注意,有两种方式。
#ifndef SOME_UNIQUE_NAME_HERE
#define SOME_UNIQUE_NAME_HERE
// contents of the header
...
#endif // SOME_UNIQUE_NAME_HERE
#pragma once
// contents of the header
#ifndef
的是方式是受C/C++语言标准支持。 #ifndef
方式依赖于宏名不能冲突。它不光可以保证同一个文件不会被包含多次,也能保证内容完全相同的两个文件不会被不小心同时包含。缺点是如果不同头文件中的宏名不小心”碰撞”,可能就会导致你看到头文件明明存在,编译器却硬说找不到声明的状况。由于编译器每次都需要打开头文件才能判定是否有重复定义,因此在编译大型项目时, #ifndef
会使得编译时间相对较长,因此一些编译器逐渐开始支持 #pragma once
的方式。
#pragma once
一般由编译器提供保证:同一个文件不会被包含多次。这里所说的”同一个文件”是指物理上的一个文件,而不是指内容相同的两个文件。无法对一个头文件中的一段代码作#pragma once
声明,而只能针对文件。此方式不会出现宏名碰撞引发的奇怪问题,大型项目的编译速度也因此提供了一些。缺点是如果某个头文件有多份拷贝,此方法不能保证它们不被重复包含。在C/C++中,#pragma once
是一个非标准但是被广泛支持的方式。
#pragma once
方式产生于#ifndef之后。#ifndef
方式受C/C++语言标准的支持,不受编译器的任何限制;而#pragma once
方式有些编译器不支持(较老编译器不支持,如GCC 3.4版本之前不支持#pragma once
),兼容性不够好。#ifndef
可以针对一个文件中的部分代码,而#pragma once
只能针对整个文件。
源文件(.cpp):
源文件主要写实现头文件中已经声明的那些函数的具体代码。需要注意的是,开头必须#include
一下实现的头文件,以及要用到的头文件。那么当你需要用到自己写的头文件中的类时,只需要#include
进来就行了。
下面写一个例子(设计一个长方体类,用它能计算不同长方体的体积和表面积):
先新建一个工程
在头文件中:
//box.h
#pragma once
class Box
{
private:
int a;
int b;
int c;
public:
int GetVolume();
int GetArea();
Box(int i, int j, int k);
};
//box.cpp
#include "box.h"
int Box::GetVolume()
{
int volume = a*b*c;
return volume;
}
int Box::GetArea()
{
int area = (a*b + a*c + b*c) * 2;
return area;
}
Box::Box(int i, int j, int k)
{
a = i;
b = j;
c = k;
}
*在.h
中声明,在.cpp
中实现。
在源文件中:
//main.cpp
#include
#include "box.h"
using namespace std;
int main()
{
Box a(5, 6, 7);
cout << "GetVolume:" << a.GetVolume() << " " << "GetArea:" << a.GetArea() << endl;
system("pause");
return 0;
}
运行输出:
GetVolume:210 GetArea:214
请按任意键继续. . .
头文件与实现文件的关系
(摘自DageKing)
关于两者以前的关系,要从N年以前说起了~ long long ago,once aupon a time .......
那是一个被 遗忘的年代,在编译器只认识.c(.cpp))文件,而不知道.h是何物的年代。
那时的人们写了很多的.c(.cpp)文件,渐渐地,人们发现在 很多.c(.cpp)文件中的声明语句就是相同的,但他们却不得不一个字一个字地重复地将这些内容敲入每个.c(.cpp)文件。但更为恐怖的是,当其中 一个声明有变更时,就需要检查所有的.c(.cpp)文件,并修改其中的声明,啊~简直是世界末日降临!
终于,有人(或许是一些人)再不能忍受这 样的折磨,他(们)将重复的部分提取出来,放在一个新文件里,然后在需要的.c(.cpp)文件中敲入#include XXXX这样的语句。这样即使某个声明发生了变更,也再不需要到处寻找与修改了---世界还是那么美好!
因为这个新文件,经常被放 在.c(.cpp)文件的头部,所以就给它起名叫做“头文件”,扩展名是.h.
从此,编译器(其实是预处理器)就知道世上除了.c(.cpp)文 件,还有个.h的文件,以及一个叫做#include命令。
虽然后来又发生很多的变化,但是这样的用法一直延续至今,只是时日久远了,人们便淡忘了当年的缘由罢了。
提到了头文件,就说说它的作用吧~
想 到了林锐GG写的高质量C/C++编程上头文件的作用的简短描述:
(1)通过头文件来调用库功能。在很多场合,源代码不便(或不准)向用户公布, 只要向用户提供头文件和二进制的库即可。用户只需要按照头文件中的接口声明来调用库功能,而不必关心接口怎么实现的。编译器会从库中提取相应的代码。
(2) 头文件能加强类型安全检查。如果某个接口被实现或被使用时,其方式与头文件中的声明不一致,编译器就会指出错误,这一简单的规则能大大减轻程序员调试、改 错的负担。
预处理是编译器的前驱,作用是把存储在不同文件里的程序模块集成为一个完整的源程序.
#include
本身只是一个简单的文件包含 预处理命令,即为把include的后面文件放到这条命令这里,除此之外,没有其它的用处(至少我也样认为).
参考文章:
c++中头文件与实现文件的关系
C++中头文件(.h)和源文件(.cpp)都应该写些什么
C/C++中#pragma once的使用