现在的位置: 首页 > 综合 > 正文

讨论一下定义和声明的区别

2013年03月22日 ⁄ 综合 ⁄ 共 1856字 ⁄ 字号 评论关闭

 

    C++primer的解释是这样的:

    变量的定义(definition):用于为变量分配存储空间,还可以为变量指定初始值。在一个程序中,变量有且仅有一个定义;

    变量的声明(declaration):用于向程序表明变量的类型和名字。定义也是声明:当定义变量时我们声明了它的类型和名字。可以通过使用extern关键字声明变量名而不定义它。

    以上解释讲得还是比较清楚的,有分配空间的叫定义,没分配空间的叫声明。好吧,你不知道什么时候分配什么时候没分配。让我们换一种说法。

    “定义也是声明”,这说明声明包括定义。所以诸如int a;extern int a;之类的一定是声明。那是不是定义还要接着往下看;

    如果程序前面都没有出现过a这个变量,这时你要使用a,你必须让程序知道你要使用a这个变量了。这时候你写入int a;以前没有a这个变量的,现在程序为了记住它,就得为他分配空间,于是这是个定义。

    如果程序包含的其他文件里已经出现过a了,这证明程序已经为a分配内存,这时你要使用a就方便很多了。你只需要告诉程序,这个a在其他地方定义过了,于是你写入extern int a;

    对于int a;来说,它既是定义又是声明;对于extern int a;来说,它是声明不是定义。一般为了叙述方便,把建立存储空间的声明称定义,而不把建立存储空间的声明称为声明.

 

[引申阅读]探讨下c++的声明和定义问题,关于extern

c++primer第四版中,53页的习题2.18中问到,extern std::string name;是属于声明还是定义?答案说的是声明。不过我认为,string类中有默认构造函数,如果该语句在函数外,那么则会自动获得储存空间,将name定义为空字符串,不知各位有何高见?

问题补充:

感谢回答我的关于extern的问题,可是还是没想通。正如一楼举的例子extern std:tring name("Zhang3Li4");我认为extern std::string name;和那句是一样的 .因为标准库中的string是有默认构造函数的,若后面什么都没有的话,就初始为空字符串

------

我刚才做了一个实验:
//a.cpp 
#include <string>

std::string i;

//b.cpp
#include <iostream>
#include <string>

extern std::string i;

int main ()
{
std::cout << i << std::endl;
}

运行结果为:

(上面是一空行:由于末尾用了endl)

如果没有a.cpp这个文件,运行出错
这是一对实验(有没有a.cpp文件)

可得出这样的结论:
a.cpp中std::string i;是定义(本来就是)
b.cpp中extern std::string i; 则是声明(你的问题)

先别急,这只是实验结果。我们还需要理论依据,那么下面就试着解释一下:

下面是另一个例子(也是第二个实验)
你应该知道内置类型(int等)如果作为全局变量时,定义的同时也就初始化了(一个内置类型有其对应的默认值;如果你将自定义类型也看成内置类型,那么就等于说,一个自定义类型有其对应的默认值(由默认构造函数完成))。如
//c.cpp
int i;

//d.cpp
#include <iostream>

extern int i;

int main ()
{
std::cout << i << std::endl;
}

那么在这里int i; 就是定义(并且初始化了i,初始值为0)
因而输出结果为
0
//这个实验的运行结果符合理论依据。
(我使用的编译器是visual studio 2008)

从这两个实验来看:(将两个“默认”等同起来)
int i;
std::string i;
都可以作为初始化i的定义性语句。
那么
extern int i;
extern std::string i; 
也具有定义行为(这个很明显与extern的用法相悖)

在以上两个试验中:int 与 string 有“区别”吗?所有的代码都一样只不过把std::string 换成了 int而已!如果你能解释int的情况,那么我想std::string问题也就迎刃而解了!

于是我个人总结出一个结论:
    不论是内置类型还是自定义类型,前面有extern关键字,如果没有显式地初始化参数(即就是自定义类型的默认构造函数被extern屏蔽了,不起初始化的作用),那么就按声明对待。

可能我的描述很混乱,希望你好好看看上面的例子,就明白了! 
注意:从这里可以看出来默认构造函数的特殊性

抱歉!评论已关闭.