笔记08:C++中头文件(.h)和源文件(.cpp)的编写

头文件(.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的使用

你可能感兴趣的:(笔记08:C++中头文件(.h)和源文件(.cpp)的编写)