关于头文件和源文件的文件类型
头文件定义函数、类、变量的声明,告诉编译器这个项目中有哪些对象,源文件才是实现代码,为了在模块间共享,一般都是把声明和实现分开,需要哪个模块时就include那个模块的h文件。
编译器对文件类型是没有严格要求的,源文件和头文件名也不需要严格保持一致,但是为了直观,便于阅读,习惯上用cpp作为源文件,h作为头文件,文件名保持一致。
需要注意的是,h中声明的函数,cpp不需要包含这个h也能编译,似乎编译器能过根据函数定义在所有模块中自动寻找实现代码,只要保证项目中函数名称唯一就可以了。而类、结构等cpp文件必须包含h,因此每个cpp包含自己的h还是必须的。
关于模块包含
由于声明和实现分开,每个cpp必须include自己的h文件。加上所有cpp必须引用预编译头。
#include "stdafx.h"
这时会引发一些混乱,一般都希望将相对不变的公共模块的h文件include到stdafx.h中,这样可以减少编译时间,也方便维护。但是假如有一个公共类模块的h文件被包含在stdafx.h中,如果该类的cpp同时包含了stdafx.h和自己的h文件,就会出现重复定义的错误。应该把cpp里去掉include自己的h文件,也可以使用下面的方法。
防止交叉重定义
在每个cpp文件中加上以下代码
VC6中:
#if !defined(XXXX_XXXX) //xxxx部分使用文件名和特殊字母定义,以作区别,且必须大写
#define XXXX_XXXX
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
.......//这里变量和函数声明部分
#endif
VS2008中简单了:
#pragma once
连接时全局对象和extern以及重定义的问题
虽然上面的方法可以避免重定义,但也只是针对单一模块来说的,由于编译时是单个模块分别编译生成obj文件的,通过上面两种方式处理编译是没问题了,因为每处理一个cpp时是不考虑其他cpp有些什么东西的,但是在链接时链接器发现了多同名对象而出错。比如说在stdafx.h中定义了一个int a;,那么所有cpp都会包含它,使得整个项目中所有obj都存在一个int a,连接时因为发现多个定义而报错。
解决方法是:
对于全局对象(包括普通变量),在stdafx.h中以extern修饰定义(也可以单独把所有全局对象以extern修饰写在一个h文件中再包含到stdafx.h),然后在任意一个cpp中声明,只在一个cpp中定义一次即可,其他cpp就可以使用该对象了。如此,连接器在遇到使用该对象时会在所有obj定位该对象。一般把全局对象的定义写在主程序所在cpp中。
关于全局函数,模块中如要调用一个全局函数必须包含了该函数的h文件,因此函数所在h文件包含到stdafx.h文件中就形成了全局函数,由于函数不是不是对象实例,不会出线连接错误。