C++初学者指南 第五篇(6)

来源:互联网 发布:upnp nat端口失败 编辑:程序博客网 时间:2024/06/16 00:40

必备技能 5.6:局部作用域
    局部作用域是由块创建的。(回忆前面讲过的块是由一对花括号括起来的)。因此,每次我们创建代码块的时候也就创建了一个新的作用域。我们可以在任何代码块中声明变量。在代码块中声明的变量我们称之为局部变量。
    局部变量只能被和它在位于同一个代码块中的代码所访问。换句话说,局部变量在其代码块之外是不会被感知的。因此,代码块之外的语句是不能访问代码块之内的对象的。从本质上来说,当我们声明了一个局部变量的时候,我们就是将这个变量本地化了,避免了对它的未经授权的访问或者修改。实际上,作用域规则提供了封装的基础。
    关于局部变量有一个很重要的点需要明确:它们只有当其所在的代码段的代码被执行的时候才存在。局部变量在其所在的代码块中被声明的时候便开始存在,它们在程序的执行离开所在代码块的时候被销毁。由于局部变量在离开其所在代码块的时候被销毁,它的值也就没有意义了。最常用的用于声明变量的代码块就是函数。每个函数都定义了一个代码块。这个代码块以函数体的左花括号开始,以函数体的右花括号结束。函数的代码和数据是函数私有的。除了调用该函数之外,别的函数中的任何语句都是不能访问它们的。(goto语句也是不能从一个函数中转跳到另外一个函数的中间的。)
    函数的函数体对程序的其它部分来说是隐藏的,它不能影响程序的其它部分,也不受程序其它部分的影响。因此一个函数的功能是完全和别的函数相独立的。换句话说,一个函数中的语句和数据是不会影响另外一个函数中的数据或者代码的,因为两个函数的作用域是不相同的。因为每个函数都定义了自己的一个作用域,所以在一个函数中声明的变量对另外函数的变量时没有任何影响的,即使变量的名字是相同的。
    例如下面的程序:

#include <iostream>using namespace std;void f1();int main(){    int val = 10; // 变量val的作用域仅限于函数main    cout << " Val in main(): " << val << '\n';    f1();    cout << " Val in main(): " << val << '\n';    return 0;}void f1(){    int val = 88;    cout << " val in f1() " << val << "\n";}


程序的输出如下:
val in main(): 10

val in f1(): 88

val in main(): 10

上面的程序中名称为val的变量被声明了两次,一次是在main()函数中,一次是在f1()函数中。main()函数中的val和f1()函数中的val没有任何的关系。这是因为每个val只能在自己所在的函数中被感知。正如程序的输出那样,即使在f1()函数中声明的变量val被赋值为88,main()函数的val的值仍为10。
    由于局部变量是在进入其所在的代码块的时候被创建,退出其所在代码块的时候被销毁,所以局部变量在函数被多次调用之间是不会保留其值的。这一点对于理解函数调用是非常重要的。当调用一个函数的时候,其中的局部变量就会被创建,当函数返回的时候,这些局部变量就会被销毁。这就意味着,在函数多次被调用之间,这些局部变量的值是不会被保留的。
    如果局部变量在声明的时候进行了初始化,那么这个变量在每次进入其所在代码块的时候都会被初始化。如下程序所示:

/*    局部变量的初始化在进入其所在代码块的时候每次都会进行*/#include <iostream>using namespace std;void f();int main(){    for( int i = 0; i < 3; i++) f();    return 0 ;}//num变量在每次调用函数f()的时候都会被初始化void f(){    int num = 99;    cout << num << "/n";    num++;// 这句代码并不会影响下一次函数f()被调用是num的值。}


程序的输出如下:
99
99
99
没有被初始化的局部变量的值是未知的,直到这个变量被赋值。


局部变量的声明可以在任何代码块中进行
    通常,我们会把函数中所需要的变量在函数一开始的时候就进行声明。这样做可以让代码的阅读者很容易地看清楚都需要哪些变量。然而,函数一开始并不是可以声明变量的唯一地方。局部变量可以在任何代码块的任何地方进行声明。这就意味着,只有进入了相应的代码块,变量才会被创建,当退出相应代码块的时候,变量就会被销毁。更进一步来说,变量所在代码块之外的任何代码都是不能访问这个变量的。为了理解这点,我们可以看看下面的程序:

//代码块中的局部变量#include <iostream>using namespace std;int main(){    int x = 19 ; // x可以被main()函数中的所有代码感知    if ( x == 19 )    {        int y = 20; // 变量y的作用域仅限于if的代码块        cout << " x + y is  " << x + y << "\n";    }    // y = 100; 错误!在这里是感知不到y的    return 0;}
上面的程序中,变量x是在main()函数开始的时候就声明的,所以main()函数中其后的所有代码都是可以访问这个变量的。在if的代码块中声明了变量y。由于代码块就定义了作用域,因此y只是对与其在同一代码块中的代码所感知。这也是在if代码块之外的语句y = 100;被注释掉的原因。如果我们去掉该语句前面的注释符,编译时就会报错,就是因为y在if代码块之外是不被感知的。在if的代码块中,x是可以被感知的,这是因为if代码块也是位于main()函数所定义的代码块中的。

   尽管局部变量通常都是在代码块开始的时候进行声明,但这不是必须的。局部变量可以在代码块中的任何地方进行声明,只要是在它被使用之前。例如,下面的程序时完全正确的:

#include <iostream>using namespace std;int main(){    cout << "Enter a number ";    int a; // 这里声明变量是完全可以的    cin >> a;    cout << "Enter a second number ";    int b; // 这里声明变量是完全可以的    cin >> b;    cout << "Product: " << a * b << '\n';        return 0;}

在这个示例中,变量a,b并没有在函数一开始就声明了,而是在需要的时候才进行声明。实际上,大部分程序员都是在函数一开始的地方进行变量的声明。这只是代码风格的问题。


名称隐藏
    当在一个内部代码块中声明了一个与外部代码块中同名的变量的时候,内部代码块中的这个变量就使得外部的这个变量被隐藏了。如下面的程序所示:

#include <iostream>using namespace std;int main(){    int i;    int j;    i = 10;    j = 100;    if ( j > 0 )    {        // 在if的代码块中,这个i使得main()函数一开始声明的i被隐藏了。        //也就是说if代码块中出现的i都是这里的i而不是main()函数一开始的声明的那个i。            int i;         i = j / 2;        cout << " inner i :" << i << "\n";    }    cout << " Outer i: " << i << '\n';    return 0;} 


上面程序的输出如下:
 inner i :50
 Outer i: 10
    上面程序中if代码块中声明的变量i就使得外部代码块中的i被隐藏了。对内部代码块中i的修改不会影响外部代码块中的i。跟进一步来说,在if的代码块之外,其内部的i就不可见了,而外部的i又恢复可见了。

函数的形参
    函数形参的作用域就局限于函数体中。因此,它们对于函数来说是局部变量。形参除了是用于接收传入实参的值之外,它们的用法完全和局部变量一样。


专家答疑:
问:关键字auto是用来干什么的?我听说是用来声明局部变量的,是这样吗?
答:C++的关键字中是有auto这个关键字的。它可以被用来声明局部变量。然而,既然所有的局部变量缺省情况下都是auto的,所以这个关键字实际上很少使用。本书中的所有示例程序也是不用这个关键字的。然而,如果你决定要使用这个关键字,只要把它放置在声明变量时类型的前面就可以了,如下:
auto char ch;
重复一次,auto关键字是可选的,本书的其它地方是不会使用它的。

原创粉丝点击