命名空间和模块化编程2
让编程改变世界
Change the world by program
使用头文件
在创建了头文件之后,只要把它的文件名用双引号括起来写在如下所示的指令里就可以导入它:#include “fishc.h”
如果没有给出路径名,编译器将到当前子目录以及当前开发环境中的其他逻辑子目录里去寻找头文件。 为了消除这种猜测,在导入自己的头文件时可以使用相对路径。如果头文件与主程序文件在同一个子目录里,则可以这么写:#include “./fishc.h”
如果头文件位于某个下级子目录里,那么以下级子目录的名字开头:#include “includes/fishc.h”
最后,如果头文件位于某个与当前子目录平行的”兄弟”子目录里,则需要这么写:#include “../includes/fishc.h”
请务必注意,Windows通常使用反斜杠作为路径名里的分隔符。 请看演示:Example (源代码下载)创建实现文件
回到Rational这个栗子,我们带大家来进一步实现模块化编程。 rational.h头文件包含Rational类的声明,但不包含这个类的实现代码。 这种分割可能刚开始接触的朋友觉得有点奇怪,但在实践中非常普遍。 因为把接口(函数的原型)和实现(函数体的定义)分开是对代码进行模块化的基本原则之一。 头文件的重要性不仅体现在它们可以告诉编译器某个类、结构或函数将有着怎样的行为,还体现在它们可以把这些消息告诉给程序员。 作为苦逼程序猿一枚,你只需看到函数的声明就可以了解到你需要知道的一切:函数的名字,它的返回值类型和它的输入参数的类型和数量。 知道了这些东西,你就可以使用那个函数了,而根本用不着关心它到底是如何工作的。 编译器就不同了,它必须读取某个类或函数的实现代码。 作为一个通用原则,应该把声明放在一个头文件里,把实现代码放在一个.cpp文件里。 现在我们就演示下rational这个程序如何分开和拼凑成一个完整的程序。C预处理器
刚才的示例程序还有一个小小的问题需要解决,就是rationcal.cpp和main.cpp文件都包含了rational.h头文件。 这意味着rational.h类被声明了两次,这显然没有必要(如果它是一个结构,声明两次还将导致编译器报错呢~) 解决方案之一是把其中一个文件里的#include删掉即可。这固然很容易可以解决的问题,但却会给今后留下麻烦。。。。。。 当然我们在这里提出是因为有更好的解决方案! 利用C++预处理器,我们可以让头文件只在这个类还没有被声明过的情况下才声明它。 [caption id="attachment_518" align="aligncenter" width="300"] 预处理器的条件指令[/caption] 以前的课程中,我们曾建议大家注释很多段代码的话用预处理的方式,比起/* */要效果好: #if 0// 这里有代码
// 这里有好多代码
// 这里有好多好多代码
// 这里有好多好多好多代码
#endif #ifndef LOVE_FISHC #define LOVE_FISHC #endif 这看起来好像没什么用,但事实却并非如此。这段代码的含义是:如果LOVE_FISHC还没有定义则定义之,看出这有什么作用了吗? #ifndef LOVE_FISHC #define LOVE_FISHCclass Rational{ … };
#endif 如果LOVE_FISHC还没有定义,这里将发生两件事儿:定义一次LOVE_FISHC,然后对Rational类做出声明等操作。 这样一来,即使包含着这段代码的文件在某个项目里被导入了100次,Rational类也只会被声明一次,因为在第一次之后LOVE_FISHC就有定义! 作为一种固定模式,这里使用的常量名通常与相应的文件名保持一致,把句点替换为下划线。 于是,rational.h文件将对应RATIONAL_H 有一个鸡蛋,掉到了地上,没有碎,猜两个字! [buy] 获得所有教学视频、课件、源代码等资源打包 [/buy] [Downlink href='http://urlxf.qq.com/?niyI73b']视频下载[/Downlink] [Downlink href='http://kuai.xunlei.com/d/LCNQDYQGVCIJ']备胎下载[/Downlink]