首页 > 编程笔记 > C++笔记 阅读:16

C++作用域(局部作用域和全局作用域)详解

在现实世界中,人们往往被限定在不同的区域内,这些区域就是国家。在 C++ 世界中,其中的居民(变量、函数、类等)同样被限定在不同的区域内,这个区域就是代码的作用域。

所谓作用域,就是某个标识符(变量名、函数名等)在程序中有效的区域。如果某个标识符在某个作用域内是有效的、可以引用的,那么这个标识符在这个作用域内是可见的。换句话说,就是标识符只在其作用域内可见。

按照作用域范围的大小,可以把作用域分为局部作用域和全局作用域。

C++局部作用域

在 C++ 中,用花括号“{ }”括起来的代码范围属于一个局部作用域。

作用域可以嵌套作用域,即一个局部作用域中包含更小的子作用域,子作用域具有较高的优先级。也就是说,在父作用域中可见的标识符在子作用域中同样可见。

在局部作用域内,一个变量或者函数从它定义的位置开始,一直作用到该作用域结束为止。常见的局部作用域有函数体,以及 if、for 等复合语句。例如:
int GetSum()
{
    // 整个函数体是一个局部作用域
    int nTotal = 0;
    for( int i = 0; i < 100; ++i )
    {
        // 函数体中的 for 循环体,是函数体所嵌套的一个局部子作用域
        // 在父作用域函数体中定义的变量,在子作用域中同样可见
        // 所以这里可以访问父作用域定义的 nTotal 变量
        nTotal += i;
    }
    i = 0; // 错误:在子作用域中定义的变量 i 在父作用域不可见
    // 在作用域中定义的变量,在整个作用域都可见
    return nTotal;
}

当然,为了更好地管理程序中的函数或者变量,也可以根据需要人为地在代码中添加一对“{ }”来构成一个局部作用域。例如:
void foo()
{
    int nNum = 0;
    {
        int nNum;
        nNum = 1;
        cout << "在局部作用域中输出:" << nNum << endl;
    }
    cout << "在函数体作用域中输出:" << nNum << endl;
}
在这个例子中,在函数体作用域的开始定义了变量 nNum,因此它的作用域从函数开始到函数结束。第二个变量 nNum 定义在一个局部作用域中,因此它的作用域是从其定义位置开始到“{ }”语句块结束。

虽然这两个使用了相同的变量名,但由于它们处在不同的作用域中,因此不会产生命名冲突。因为子作用域的优先级高于父作用域,如 nNum = 1 赋值语句实际上是对第二个局部作用域中的变量 nNum 进行赋值,不会影响父作用域中的 nNum 变量,所以最后输出函数作用域内的变量 nNum 的值仍是最开始的初始值。

虽然 C++ 语法上允许这种编程方式,但为了避免代码在语义上的混淆,最好不要在一个函数中定义两个同名的变量。

C++全局作用域

与局部作用域相对应的是全局作用域。如果某个变量或者函数不在任何局部作用域内,它就处于全局作用域中,被称为全局变量或者全局函数。

全局作用域覆盖了整个源文件范围,其中定义的变量或者函数,从它们被定义时开始,直到源文件结束之前都是可见的。例如,在一个源文件中,可以这样使用全局变量和全局函数:
// 定义一个全局变量
int gN;

// 定义一个全局函数
void GlobalFunc()
{
    for( int i = 0; i < gN; ++i )  // 访问全局变量 gN
    {
        //...
    }
}

int main()
{
    gN = 3;  // 访问全局变量
    GlobalFunc();  // 调用全局函数
    //...
    return 0;
}
在这个例子中,在源文件开始定义的变量 gN 因为没有在任何局部作用域,所以它的作用域就是全局作用域,覆盖整个源代码文件,可以在文件后面的任何位置访问这个变量。而 GlobalFunc() 是一个全局函数,在其定义之后,可以在同一个源文件的任何位置调用这个函数。

我们知道,C++ 程序通常会分解为多个源文件和头文件。全局作用域内的变量或者函数只在自身定义所在的源文件范围内可见。但如果希望在一个源文件中使用另一个源文件中定义的全局变量或函数,该怎么办呢?

很简单,只需使用 extern 关键字重新声明一次在其他源文件中定义的变量或函数即可。extern 关键字表示这是一个外部(extern)的变量或函数,编译器会在其他源文件中查找这个变量或函数的具体定义。

例如,在 Global.cpp 文件中定义一个全局变量和全局函数:
// Global.cpp: 定义全局变量和全局函数
// 用 static 声明的本地静态函数,只能在当前源文件中使用
static int Power(int n)
{
    return n*n;
}

// 全局变量
int gTotal = 0;

// 全局函数
int PowerSum(int a, int b)
{
    return Power(a) + Power(b);
}

如果想在另一个源文件中使用上述代码的全局变量和全局函数,只需用 extern 关键字对它们重新声明一次,然后就可以开始使用了:
// main.cpp: 使用全局变量和全局函数
// 在变量声明前加上 extern 关键字,重新声明全局变量
extern int gTotal;
// 在函数声明前加上 extern 关键字,重新声明全局函数
extern int PowerSum(int a, int b);

int main()
{
    // 使用全局变量和全局函数
    gTotal = PowerSum(2, 3);

    return 0;
}
这样,通过 extern 关键字,全局变量或全局函数就可以超越单个源文件的限制,成为整个程序范围内的共享资源,真正实现全局访问,如下图所示。


图 1 多个源文件共享全局变量和全局函数

相关文章