VC++中关于全局量的定义有两种比较好的方法(附:extern)
http://blog.csdn.net/loyal_baby/article/details/4067223
声明用于向程序表明变量的类型和名字。定义也是声明:当定义变量时我们声明了它的类型和名字。可以通过使用extern关键字声明变量名而不定义它。不定义变量的声明包括对象名、对象类型和对象类型前的关键字extern:
extern int i; // declares but does not define i
int i; // declares and defines i
An extern declaration is not a definition and does not allocate storage. In effect, it claims that a definition of the variable exists elsewhere in the program. A variable can be declared multiple times in a program, but it must be defined only once.
extern 声明不是定义,也不分配存储空间。事实上,它只是说明变量定义在程序的其他地方。程序中变量可以声明多次,但只能定义一次。
A declaration may have an initializer only if it is also a definition because only a definition allocates storage. The initializer must have storage to initialize. If an initializer is present, the declaration is treated as a definition even if the declaration is labeled extern:
只有当声明也是定义时,声明才可以有初始化式,因为只有定义才分配存储空间。初始化式必须要有存储空间来进行初始化。如果声明有初始化式,那么它可被当作是定义,即使声明标记为 extern:
extern double pi = 3.1416; // definition
Despite the use of extern, this statement defines pi. Storage is allocated and initialized. An extern declaration may include an initializer only if it appears outside a function.
虽然使用了 extern ,但是这条语句还是定义了 pi,分配并初始化了存储空间。只有当 extern 声明位于函数外部时,才可以含有初始化式。
Because an extern that is initialized is treated as a definition, any subseqent definition of that variable is an error:
因为已初始化的 extern 声明被当作是定义,所以该变量任何随后的定义都是错误的:
extern double pi = 3.1416; // definition
double pi; // error: redefinition of pi
Similarly, a subsequent extern declaration that has an initializer is also an error:
同样,随后的含有初始化式的 extern 声明也是错误的:
extern double pi = 3.1416; // definition
extern double pi; // ok: declaration not definition
extern double pi = 3.1416; // error: redefinition of pi
The distinction between a declaration and a definition may seem pedantic but in fact is quite important.
声明和定义之间的区别可能看起来微不足道,但事实上却是举足轻重的。
In C++ a variable must be defined exactly once and must be defined or declared before it is used.
在 C++ 语言中,变量必须且仅能定义一次,而且在使用变量之前必须定义或声明变量。
VC++中关于全局量的定义有两种比较好的方法。
第一种
新建一个Generic Class类,如CGlobals。会产生一个Globals.h头文件和一个Globals.cpp文件,在ClassView中会产生一个CGlobals类。由于主要目的是利用产生的.h和.cpp文件,所以,将两个文件中关于类声明和定义的部分都删除或注释掉,但保留其他语句,此时ClassView中的CGlobals类消失。
对于全局结构体定义,首先在Globals.h头文件中构造结构体,用typedef方式,如:
typedef struct tagLineType
{
int ID;
CString Type;
double r0;
double x0;
}LINETYPE; // 名称可随便
而后,在Globals.h头文件:
extern LINETYPE *lineType; // 注意,这里不能再初始化
而后,在Globals.cpp文件中:
LINETYPE *lineType = NULL; // 注意,在这里初始化
对于普通全局变量(如int型)定义,首先在Globals.h头文件中:
extern int iTime; // 注意,这里不能再初始化
然后在Globals.cpp中:
int iTime = -1; // 注意,在这里初始化
对于全局常量定义,首先再在Globals.h头文件中:
extern const int UB;
而后Globals.cpp中:
const int UB = 10;
以上是第一种方法,是我自己总结试验成功的。用该方法定义完毕后,无论哪个.cpp文件要用到全局变量,只需在该.cpp文件中#include "Globals.h"即可,而无需再在.cpp文件中extern,所有全局变量、全局常量、全局结构体都是可见的。该方法的总体思路是,象theApp那样,在.cpp中定义,在.h头文件中extern声明。另外要注意,变量的初始化一定在Globals.cpp文件中,而不能在Globals.h头文件中。
第二种
新建一个.h头文件,如Globals.h,将所有要定义的全局变量在该头文件种定义。而后新建另一个头文件,如GlobalsExt.h,将所有在Globals.h中定义的全局变量extern声明,同样,初始化工作要在Globals.h中进行。定义完毕后,在第一次要使用全局变量的.cpp文件中,#include "Globals.h"头文件,在以后要使用全局变量的.cpp文件中,#include "GlobalsExt.h"头文件。
该方法据说是一种比较规范的定义方法,网上有相关文章。但我没有试成功过,总是提示有重复定义。
1. 定义和声明的区别(变量,在被使用前必须被定义或声明)?
- 声明用于向程序表明变量的类型和名字;
- 定义本身也是声明,当定义变量时声明了它的类型和名字;
- 变量必须且只能被定义一次,但是可以被声明多次;
- 若想只声明变量而不定义它,就必须在变量类型前加extern关键字,并且不可以使用初始化式(即赋值表达式)。仅仅是声明而不定义变量时,系统不会分配存储空间。
- 只有当extern声明位于函数外部(全局)时,才可以含有初始化式;
- 以下是几个例子:
- extern int i; // 带有extern关键字,且没有初始化式,所以仅仅声明了变量i,并没有定义它
- int i; // 不含extern,所以定义并声明了变量i
- extern double pi = 3.14; // 虽然有extern,但是有了初始化式,所以是定义并声明了变量pi
2. 定义和声明,哪些应写在头文件中,哪些应写在源文件中?
- 大多数情况下,头文件用于声明而不是用于定义,同一个程序中有两个或以上文件含有同一个名称的全局变量的定义都会导致多重定义链接错误。因为头文件经常会包含在多个源文件中,因此不应该含有变量或函数的定义;
- 对于上面的头文件不应含有定义这个规则,有三个例外:头文件可以定义类、值在编译时就已知的const对象和inline函数。这些实体可以在多个源文件中定义,只要每个源文件中的定义是相同的;
- 两种重复定义编译器报错的情况:
1) 同一个源文件包含的多个头文件中,头文件本身存在多重包含的现象
- //程序来源:孙鑫《VC++深入详解》P58
- //animal.h
- class animal
- {
- public:
- animal();
- ~animal();
- void eat();
- void sleep();
- virtual void breathe();
- };
- //fish.h
- #include "animal.h"
- class fish : public animal
- {
- public:
- fish();
- ~fish();
- void breathe();
- };
- //main.cpp
- #include "animal.h"
- #include "fish.h"
- void fn(animal *pAn)
- {
- }
- void main()
- {
- }
编译结果:error C2011: 'animal' : 'class' type redefinition
报错原因:在main.cpp中包含了animal.h和fish.h两个头文件,而在fish.h中也包含了animal.h,因此相当于在main.cpp中对animal.h进行了多重包含。编译时,animal.h先后被展开了两次,第一次展开时定义了animal类,第二次展开时发现此类已被定义,因此报错,animal类被重复定义。
解决方法:可以通过定义预处理变量,见下面的例子:
- //animal.h
- #ifndef ANIMAL_H
- #define ANIMAL_H
- class animal
- {
- public:
- animal();
- ~animal();
- void eat();
- void sleep();
- virtual void breathe();
- };
- #endif
检测ANIMAL_H预处理变量是否已定义,若否,则满足判断条件,#ifndef ANIMAL_H之后的所有语句都被执行,直到发现#endif;若是,则不满足判断条件,该#ifndef语句和#endif之间所有代码都被忽略。这样就可以保证animal类只被定义一次。
2) 不同源文件包含同一个头文件,且头文件中定义了全局变量
- //add.h
- #include <iostream.h>
- int a=0, b=0, c=0; // 定义了三个全局变量
- int Add(int, int, int); // 声明了一个函数//add.cpp#include "add.h"
- int Add(int x, int y, int z)
- {
- z = x + y;
- cout<<"add.cpp: a = "<<a<<endl;
- cout<<"add.cpp: c = "<<z<<endl;
- return 1;
- }
- //main.cpp
- #include "add.h"
- extern int a;
- extern int b;
- extern int c;
- int main(void)
- {
- a = 1;
- b = 2;
- int ReturnValue = Add(a, b, c);
- cout<<"main.cpp: c = "<<c<<endl;
- return ReturnValue;
- }
编译结果:error LNK2005: "int c" (?a@@3HA) already defined in add.obj
error LNK2005: "int b" (?b@@3HA) already defined in add.obj
error LNK2005: "int a" (?c@@3HA) already defined in add.obj
fatal error LNK1169: one or more multiply defined symbols found
报错原因:add.cpp和main.cpp同时包含了add.h,而add.h中定义了三个全局变量a、b、c,前文提到的,同一个程序中有两个或以上文件含有同一个名称的全局变量的定义都会导致多重定义链接错误。
解决方法:将变量定义在源文件中,而在头文件中只进行声明(不定义),见下面的例子:
- //add.h
- #include <iostream.h>
- extern int a; //变量的声明
- extern int b;
- extern int c;
- int Add(int, int, int); //函数的声明
- //add.cpp
- #include "add.h"
- int Add(int x, int y, int z) //函数的定义
- {
- z = x + y;
- cout<<"add.cpp: a = "<<a<<endl;
- cout<<"add.cpp: c = "<<z<<endl;
- return 1;
- }
- //main.cpp
- #include "add.h"
- int a=0, b=0, c=0; //变量的定义
- int main(void)
- {
- a = 1;
- b = 2;
- int ReturnValue = Add(a, b, c);
- cout<<"main.cpp: c = "<<c<<endl;
- return ReturnValue;
- }

浙公网安备 33010602011771号