C++ 变量作用域小探索

 

最近开始学习C++, 刚好看到作用域这一块儿,遇到一些好像跟C不一样的地方(或者是一样的,,只是以前没注意罢了),比如说定义嵌套覆盖。。

写了一个小例子

 

#include

int num1 = 1;
std::string str1 = "David";

//display the value of str1
void display();

int main()
{
std::cout << "before definiton in main, num1 is " << num1 << std::endl; int num1 = 2; std::cout << "after definition in main, num1 is " << num1 << std::endl; std::cout << "before definiton in main, str1 is " << str1 << std::endl; display(); int str1 = 3; std::cout << "after definition in main, str1 is " << str1 << std::endl; display(); int num2 = 4; std::cout << "first declaration in main, num2 is " << num2 << std::endl; //std::string num2 = "Daisy"; //compile error:conflicting declaration //int num2 = 5; //compile error:redeclaration //statement scope for(int num1 = 0, sum = 0; num1 < 1; num1++) { sum += num1; std::cout << "num1 is " << num1 << std::endl; } std::cout << "num1 is " << num1 << std::endl; //statement scope for(int num2 = 0, sum = 0; num2 < 2; num2++) { sum += num2; std::cout << "num2 is " << num2 << std::endl; } std::cout << "num2 is " << num2 << std::endl; //block scope { std::string str1 = "Daisy"; std::cout << str1 << std::endl; display(); } std::cout << str1 << std::endl; } void display() { std::cout << "in display() str1 is " << str1 << std::endl; }

 

 

然后输出结果是

 

1.首先对于num1这个变量,已经在第三行定义成了全局变量并初始化为1,然后在main函数里第11行,打印输出很显然就是

“before definiton in main, num1 is 1”

然后我们在第12行把它重新定义一下,赋值为2,在第13行里打印出的结果就是

"after definition in main, num1 is 2"

惊讶了一下,居然可以这样用(或许是我以前没有这么写过C吧,不知道在C里面是否也可以这样用,忘记测试了)。对于已经定义了的变量,再定义一次,难道不会引起重复定义错误吗??那编译器不会迷惑吗?但是结果很显然的摆在那里,没有错误,并且结果也是预想的结果。

我就在想,会不会是因为类型一样,所以编译器忽略这些什么的。。。然后就想了一个比较BT的招儿,那就是把类型也给他换了,只保证名字一样,看结果如何。这就出现了第二个测试点。

 

2.对于在第四行第一次定义的string变量 str1,赋值为“David”。在main函数里第15行打印一下,很显然结果是

"before definiton in main, str1 is David", 就如同结果图片里面的第三行输出。

接着我调用了一下display()函数,主要是打印一下str1这个全局变量,结果也很显然是

"in display() str1 is David"

好了,现在我在第17行,重新定义了一下str1,这次不止改变了值,连类型也改变了,把它定义为了int并赋值为3,而全局变量是string类型的。然后打印,编译器没有报错,正常打印。

“after definition in main, str1 is 3”,然后我又调用了一下displays()函数,想看看是不是全局变量的也改变了,打印结果是

"in display() str1 is David",说明全局变量并没有被改变!

 

通过第1和第2两点,我总结了一下。全局变量虽然它的作用域是全局,但是在函数里面可以被屏蔽(不知道该找什么形容词),也就是说如果函数里面没有重新定义这个全局变量,那么对该变量的使用跟正常使用变量没什么区别。但是如果在函数里面重新定义了该变量,不管类型是不是一样,那么在二次定义以后,该函数对其的使用则是使用其重新定义以后的变量,但是这种使用并不改变全局变量,只是全局变量暂时被屏蔽了而已。

 

然后我在想,是不是只有全局变量可以这样被二次定义,然后就做了第三个试验

3.在main函数里第21行,定义了一个int变量num2,赋值为4,然后打印一下。结果很显然是

"first declaration in main, num2 is 4"

接着我试着在后面重新定义一下num2,首先把它的类型改变,编译,果断报错,“冲突的定义”。

然后我在想,是不是太激进了,于是只改变其值,不改变类型,但是不是直接赋值,而是重新定义一下并赋值。如24行所示。编译,果断报错,“重复定义”。

通过测试点3,说明了在同一作用域里的变量是不能重复定义的,只能定义一次。这个倒很正常,,,,因为写C的时候,这些都很熟悉了,只是前面遇到了“屏蔽”的情况,所以想顺道测试一下是不是同一作用域下也能“屏蔽”。

既然做都做了,那么也顺便测试一下语句作用域的情况吧,不是还有个叫statement scope的作用域么,于是有了测试点4

4.首先在一个循环里面,重新定义一下num1,我想,既然可以从“外”往“里”屏蔽,那么从“里”往“里的里”也应该能屏蔽,果然,在for里面,num1的值是在语句作用域里的值,跳出循环以后,再打印就是函数作用域里的num1值了(不是全局的值,它已经被main里的屏蔽,这点从打印的是2 而不是 1就看得出来)

然后测试了一下num2,这个结果就很显然了,既然“外”到“里的里”都都能屏蔽,那么只过度了一层的“里”到“里的里”,显然也能成功,打印结果也显而易见。

接着很蛋疼的测试了一下,直接用花括号包含起来的块作用域(能不能这么称呼啊。。。),把str1重新定义为了“Daisy”,然后打印,结果是“Daisy”,说明屏蔽成功,然后调用display()函数,打印的是“in display() str1 is David”,说明全局变量并没有被改变,那么对于str1的重定义是改变的什么呢,我觉得就是改变的main函数里的str1啦,我们在main函数里把str1重新定义为了int类型,然后在这个块里面,我们又屏蔽了这个int的定义,然后用string重新定义了。但是出了这个块以后,回到了main函数作用域,那我们打印str1的时候,当然又回到了main函数作用域里对他的定义,那就是int类型,并且值为3.

 

好啦,总结完毕,也对作用域有了更一步理解,,,其实说得挺模糊的。。。嘎嘎。

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.