c/c++头文件的作用及使用规则

头文件是C/C++程序不可缺少的组成部分。使用头文件,应该注意头文件的作用和用法相关知识点。

1.头文件的作用

C/C++编译器采用的是分离编译模式。在一个项目中,有多个源文件存在,但是它们总会有一些内容是相同的,如使用相同的用户自定义类型、使用了相同的全局变量等。因此,将这些内容抽取出来放到头文件中,然后在提供给各个源文件包含,就可以避免这些内容的重复书写,提高编程效率和代码安全性。

所以,设立头文件的目的主要是:提供全局变量、全局函数的声明或提供公用数据类型的定义,从而实现分离变异或代码复用。

在这里,有一个判断头文件中的内容是否合适的简单准则:规范的头文件应该被多个源文件包含而不引发编译错误。 
概括的说,头文件有如下三个作用。 
(1)加强类型检查,提高代码得类型安全性。 
在C++中使用头文件,对自定义类型的安全也是非常重要的。虽然,在语法上,同一个数据类型(如一个class)在不同的源文件中书写多次是允许的,程序员认为他们是同一个自定义类型。但是,由于用户自定义类型不具有外部连接特性,编译器并不关心该类型的多个版本之间是否一致,这样会导致逻辑错误的发生。考察如下程序。

//source1.cpp
#include <iostream>

class A{
private:
    char num;
public:
    A();
    void show();
};

void A::show(){
    std::cout<<num<<std::endl;
}

void see(A& a){
    a.show();
}
//end source1.cpp

//source2.cpp
#include <iostream>

class A{
private:
    int num;
public:
    A(){num=5;};
    void show();
};

void see(A& a);

int main(){
    A a;
    see(a);
    getchar();
}
//end source2.cpp
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

这个程序能够顺利通过编译并正确的运行,在在构成项目的两个源文件中,对class A的定义出现了一点小小的不一致。两个源文件中,成员变量num一个是char类型,一个是int类型,这就导致了输出了一个特殊得字符。

如果将class A的定义放到一个头文件中宏,用到class A的源文件都将这个头文件包含进来,就可以绝对保证数据类型的一致性和安全性。

(2)减少代码的重复书写,提高编写和修改程序的效率。 
在程序开发的过程中,对某些数据类型或者接口进行修改是难免的,使用头文件,只需要修改头文件中的内容,就可以保证修改在所有源文件中生肖,从而避免了繁琐易错的重复修改。

(3)提供保密和代码重用的手段。 
头文件也是C++代码虫蛹即只中不可缺少的一种手段,在很多场合,源代码不便(或不准)向用户公布,只要向用户提供头文件和二进制的库即可。用户只需要按照头文件的接口声明来调用库功能,而不必关心接口是怎么实现的,编译器会从库中提取相应的代码。


2.头文件的用法

2.1头文件中的内容

设立头文件的目的主要是:提供全局变量、全局函数的声明或提供公用数据类型的定义,从而实现分离变异或代码复用。

因此,下面的这些内容应该放在头文件中:外部函数原型声明、全局变量声明、自己顶一顶额宏和类型等。

下面这些内容不应该放在头文件中:全局变量的定义、外部变量的定义、静态变量和静态函数的的定义、在类体之外的类成员函数的定义等。

头文件应该包含和不应该包含什么内容,都是为了满足头文件被多个源文件包含而不引发编译错误。

2.2使用系统提供的头文件

C语言系统环境提供的头文件都是以.h结尾的,如stdio.h等。C++语言最初的目的是成为一个“更好的C”,所以C++语言沿用了C语言头文件的命名习惯,将头文件后面加上.h标志。随着C++语言的发展,C++加入了全新的标准库,为了避免与C发生冲突,C++引入了命名空间来避免名称冲突,也去掉了头文件的.h后缀。

于是,在一段时间里,很多头文件有两个版本,一个以.h结尾,而另一则不是,如iostream.h(位于全局名字空间)和iostream(位于名字空间std)。程序员编写程序也有不同的选择,很多C++源程序以这样的语句开始:

#include <iostream.h>
  • 1

而另一些,则以这样的两条语句开始:

#include <iostream>
using namespace std;
  • 1
  • 2

这种现象有些混乱,于是C++标准委员会规定,旧C头文件(如stdio.h)和C++中新的C头文件(如cstdio)继续使用,但是旧的C++头文件(如iostream.h)已被废弃,一律采用C++新标准规定的头文件(如iostream)。 
另外,在包含系统头文件的时候,应该使用<>(尖括号)而不是””(双引号)。例如应该这样包含头文件iostream:

#include <iostream>
  • 1

而不是这样:

#include “iostream”
  • 1

双引号””用来包含自定义的头文件,用它来包含系统头文件是一种不良的编程习惯。

2.3避免头文件被重复包含

C++语言中的内容,有的在项目一级的范围内只能出现一次,如全局变量的定义、函数的定义等。有的可以在项目一级的范围出现多次,但在一个源文件中只能出现一次,如class的定义等;还有的在一个源文件中可以出现多次,如函数声明等。注意,项目一级可以理解为项目的所有源文件。由于事先无法无法确定头文件的内容,应该不免在一个源文件中对同一头文件包含多次,以免引起重定义错误。考察如下程序。

//header1.h
class A{
int num;
public:
A();
void show();
};
//end header1.h

//header2.h
#include “header1.h”
class B{
A a;
public:
    void disp();
};
//end header2.h

//main.cpp
#include <iostream>
#include “header1.h”
#include “header2.h”
A::A(){
    num=5;
}
void A::show(){
    std::cout<<num<<std::endl;  
}
int main(){
A a;
a.show();
}
//end main.cpp
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

这个程序无法通过编译,原因是class A在源文件main.cpp中被定义了两次,这是由于头文件header2.h包含了header.1,在源文件main.cpp包含了header2.h,也包含了header1.h,这就导致header1.h在main.cpp中被包含了两次,也就造成了class A重复定义。

一个头文件被别的源文件重复包含是经常发生的,如何避免某个头文件被重复包含呢?利用条件编译轻松解决。在头文件的开始加入:

#ifndef HEADER_NAME
#define HEADER_NAME
  • 1
  • 2

在头文件的结尾加上:

#endif
  • 1

HEADER_NAME指的是头文件的名称。将这些条件编译预处理指令加入上面的示例程序中的两个头文件,问及即可解决。 
阅读以上的示例代码,需要注意一下几点:

(1)条件编译指令#ifndef HEADER_NAME和#endif的意思是:如果条件编译标志HEADER_NAME没有定义的话,就编译#ifndef和#endif之间的程序段,否则就忽略它。课件,头文件header1.h只要被包含一次,条件编译标志宏HEADER_NAME就会被定义,这样就不会被再次包含。

(2)iostream是系统提供的头文件,所以被包含时在头文件两边使用尖括号<>,而header1.h和header2.h是用户自定义的头文件,被包含时使用双引号””。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值