作为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++编译期,只编译源文件,而头文件只是复制粘贴的一个过程,而预编译头是强制在源文件的第一行,所以,其它的所有

头文件,通过这种方式,导致其它所有的头文件都包含了。

因此:

  1.  其它的头文件,可以直接使用预编译头的声明的类型, 不需要再主动包含。
  2.  预编译头,只能在源文件的第一行包含,不需要再其它头文件主动包含,虽然不会报错,但是不需要。
  3.  预编译头的修改,会导致所有源文件重新编译,因此我们一般只在预编译包含不会被修改的文件,例如,Qt库,标准库。
  4.  预编译头还会被单独预处理为: 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文件。

 

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。