1.C++中的文件类型
在一个C++程序中,只包含两类文件——.cpp文件和.h文件
其中,.cpp文件被称作C++源文件,里面放的都是C++的源代码
而.h文件则被称作C++头文件,里面放的也是C++的源代码
2.C++的编译方式
C+ +语言支持“分别编译”(separate compilation)
一个程序所有的内容,可以分成不同的部分分别放在不同的.cpp文件里。
.cpp文件里的东西都是相对独立的,在编 译(compile)时不需要与其他文件互通,只需要在编译成目标文件后再与其他的目标文件做一次链接(link)就行了。
比如,在文件a.cpp中定义 了一个全局函数“void a() {}”,而在文件b.cpp中需要调用这个函数。即使这样,文件a.cpp和文件b.cpp并不需要相互知道对方的存在,而是可以分别地对它们进行编译, 编译成目标文件之后再链接,整个程序就可以运行了。
在文件b.cpp中,在调用 “void a()”函数之前,先声明一下这个函数“void a();”,就可以了。
这是因为编译器在编译b.cpp的时候会生成一个符号表(symbol table),像“void a()”这样的看不到定义的符号,就会被存放在这个表中。再进行链接的时候,编译器就会在别的目标文件中去寻找这个符号的定义。一旦找到了,程序也就可以 顺利地生成了。
简而言之,C++文件是独立的,在编译每一个文件的时候,通过符号表寻找相应的符号(函数)的定义,再链接过去,就可以实现文件的链接,以及不同函数之间的调用。
3.“定义“和“声明“”
“定义”:把一个符号完完整整地描述出来:它是变 量还是函数,返回什么类型,需要什么参数等等。
“声明”:只是声明这个符号的存在,即告诉编译器,这个符号是在其他文件中定义的,我这里先用着,你链接 的时候再到别的地方去找找看它到底是什么吧。
考虑一下,如果有一个很常用的函数“void f() {}”,在整个程序中的许多.cpp文件中都会被调用,那么,我们就只需要在一个文件中定义这个函数,而在其他文件中声明这个函数就可以了。但是,如果函数多了,比如是一大堆的数学函数,有好几百个,那怎么办?能保证每个程序员都可以完完全全地把所有函数的形式都 准确地记下来并写出来吗?
4.头文件的引入
很显然,答案是不可能。但是有一个很简单地办法,可以帮助程序员们省去记住那么多函数原型的麻烦:我们可以把那几百个函数的声明语句全都先写好,放在一个文件里,等到程序员需要它们的时候,就把这些东西全部copy进他的源代码中。
所谓的头文件,其实它的内容跟.cpp文件中的内容是一样的,都是 C++的源代码。但头文件不用被编译。我们把所有的函数声明全部放进一个头文件中,当某一个.cpp源文件需要它们时,它们就可以通过一个宏命令 “#include”包含进这个.cpp文件中,从而把它们的内容合并到.cpp文件中去。当.cpp文件被编译时,这些被包含进去的.h文件的作用便发 挥了。
总而言之,是将定义放在一个.cpp文件里,将声明放在一个.h文件里,再在需要使用的地方,用宏命令#include将文件包含进来,两个cpp文件分别编译,最后进行链接。
5.c++标准头文件
#include <algorithm> //STL 通用算法
#include <bitset> //STL 位集容器
#include <cctype> //字符处理
#include <cerrno> //定义错误码
#include <cfloat> //浮点数处理
#include <ciso646> //对应各种运算符的宏
#include <climits> //定义各种数据类型最值的常量
#include <clocale> //定义本地化函数
#include <cmath> //定义数学函数
#include <complex> //复数类
#include <csignal> //信号机制支持
#include <csetjmp> //异常处理支持
#include <cstdarg> //不定参数列表支持
#include <cstddef> //常用常量
#include <cstdio> //定义输入/输出函数
#include <cstdlib> //定义杂项函数及内存分配函数
#include <cstring> //字符串处理
#include <ctime> //定义关于时间的函数
#include <cwchar> //宽字符处理及输入/输出
#include <cwctype> //宽字符分类
#include <deque> //STL 双端队列容器
#include <exception> //异常处理类
#include <fstream> //文件输入/输出
#include <functional> //STL 定义运算函数(代替运算符)
#include <limits> //定义各种数据类型最值常量
#include <list> //STL 线性列表容器
#include <locale> //本地化特定信息
#include <map> //STL 映射容器
#include <memory> //STL通过分配器进行的内存分配
#include<new> //动态内存分配
#include <numeric> //STL常用的数字操作
#include <iomanip> //参数化输入/输出
#include <ios> //基本输入/输出支持
#include <iosfwd> //输入/输出系统使用的前置声明
#include <iostream> //数据流输入/输出
#include <istream> //基本输入流
#include <iterator> //STL迭代器
#include <ostream> //基本输出流
#include <queue> //STL 队列容器
#include <set> //STL 集合容器
#include <sstream> //基于字符串的流
#include <stack> //STL 堆栈容器
#include <stdexcept> //标准异常类
#include <streambuf> //底层输入/输出支持
#include <string> //字符串类
#include <typeinfo> //运行期间类型信息
#include <utility> //STL 通用模板类
#include <valarray> //对包含值的数组的操作
#include <vector> //STL 动态数组容器