作为Qt开发者,我们必须了解C++工程和Qt工程的编译过程,理解编译过程不仅仅能够防止一些奇奇怪怪的错误产生,更多的它能提高我们编码的效率。
编译过程
C++一般只编译源文件(.cpp、.cc、.c等等),vs选择一个源文件按Ctrl+F7,又或者使用右键菜单单独编译该源文件,而一般头文件是没有编译这个选项。
源文件右键菜单 头文件 右键菜单
记住,C++工程,只编译源文件,头文件是被间接包含编译的。
头文件包含
一般包含某个头文件,等价于将头文件复制粘贴到指定的位置上。例如:
xx.h
return 0;
main.cpp
int func(){
#include “xx.h”
}
为什么举这样一个不实用的例子,就是想表达,头文件包含的原理是什么,因此我们不仅仅可以
在源文件的头部包含头文件,甚至可以在源码中包含。
/P
我们可以在源码的命令行中的其他选项中加上命令行 : /P
那么按CTRL+F7单独编译该源文件,不在生成xx.obj文件,而是生成xx.i文件,一般该文件在xx.cpp目录下。
打开该文件,它会将该源文件所有间接或直接包含的头文件替换,实际生成比较复杂,动不动就几十万代码。

通过这个.i文件,我们才能看到这个源文件的全貌,使用这种手段,可以用于分析和解决一些重定义的问题。
预编译头
首先,我们还是需要强调一句话,就是C++编译期,只编译源文件。
当一个工程指定预编译头时,则强制每一个源文件都必须在源文件的第一行有效代码,包含预编译头,一般预编译头为stdafx.h。
那我们在一个头文件中,如果使用到了另一个头文件申明的东西,最直接和靠谱的方法,是在这个头文件包含另一个头文件,
但是按照C++的编译过程,其实,如果,我们能够保证在包含当前这个头文件之前,包含了另外一个头文件,也是不会有问题的。
但是这种做法,就比较麻烦,但是预编译头,就不一样,它是被强制在源码的第一行的包含的,因此任何其它的头文件,都会被
间接包含了预编译头。
总结一下, C++编译期,只编译源文件,而头文件只是复制粘贴的一个过程,而预编译头是强制在源文件的第一行,所以,其它的所有
头文件,通过这种方式,导致其它所有的头文件都包含了。
因此:
- 其它的头文件,可以直接使用预编译头的声明的类型, 不需要再主动包含。
- 预编译头,只能在源文件的第一行包含,不需要再其它头文件主动包含,虽然不会报错,但是不需要。
- 预编译头的修改,会导致所有源文件重新编译,因此我们一般只在预编译包含不会被修改的文件,例如,Qt库,标准库。
- 预编译头还会被单独预处理为: stdafx.pch, 目的是加速编译过程,还记得上面的.i文件,预编译头能够极大减少需要编译的内容。
头文件简化
上面已经清楚,编译器只编译源文件,头文件是被间接包含进来的,如果一个头文件被多个源文件包含,如果修改了该头文件,则就源文件
间接被修改一样,因此,所有包含该头文件的源文件,都需要重新编译。因此为了加速编译过程,通常我们会选择,尽可能少的去修改头文件,
或者使用手段减少头文件的修改。
- 减少头文件的对其它头文件的包含,头文件包含头文件会产生链式反应。
通常,我们只包含基类和一些基础库的头文件,在业务相关的头文件之间,不要直接包含,否则会出现以下问题:
1. 环包含,A头文件包含B头文件, B头文件包含了A头文件,编译会报错。
2. 重定义,集成开发,一般我们要求不能定义重名的类,但是如果过于工程过于复杂时,会不可避免出现重定义。
这种情况,我们可以通过现在头文件包含防止,限制其范围,避免重定义的头文件出现交叉。
3. 链式包含,会导致无限的扩大编译范围,减少链式包含,会极大的减少编译范围,从而减少编译时间。
4. 减少头文件包含,也遵循了设计原则的单一性原则和最少知道原则。
因此,业务类包含,尽可能在源文件包含,如果在头文件中使用了类的引用或者指针,可以在头文件进行类声明。
另外,我在Q_Q和Q_D的合理使用一篇也讲到了头文件简化的技巧。目的也是一样的。
总结一下: 我们尽可能保证,头文件中只输出外面需要的接口,不要间接的暴露一些不相关的东西。
命名空间
命名空间的作用,是为了防止重定义,经典性重定义错误,是标准库和windows库之间的重定义错误,遇到了,感觉不可纠正一样。
但是标准库中的东西,都是使用命名空间std包含的。
我们通常,会使用using namespace的方式,使用命名空间,但是值得注意的是: 一定不要在头文件使用using namespace。这是编码规范,
因为,你在头文件使用using namespace, 这和命名空间的作用相悖的。
Qt的预处理
我在Qt编程一篇有讲到Qt工程在编译时,有3大预处理,分别是:
moc.exe 编译有Q_OBJECT宏的头文件或者源文件。
uic.exe 编译xx.ui文件
rcc.exe编译xx.qrc文件。
评论(0)