“函数最外层作用域的局部变量不能使用与任何参数相同的名称”是什么意思?

13

我一直在阅读C++ Primer第五版。在第6.1章节函数参数列表的第三段中,它写道:“此外,在函数最外层作用域的局部变量可能不能使用与任何参数相同的名称”。这是什么意思?

我不是母语为英语的人。我不理解“函数最外层作用域”的实际含义。

5个回答

24
函数的最外层作用域是定义函数主体的块。您可以在其中放置其他(内部)块,并在其中声明变量,这些变量仅适用于该块。内部块中的变量与外部块或函数参数中的变量名称相同,它们将隐藏外部作用域中的名称。外部块中的变量无法与函数参数具有相同的名称。
为了说明:
void f(int a)           // function has a parameter
{                       // beginning of function scope
    int b;              // OK: local variable
    {                   // beginning of inner block
        int a;          // OK: hides parameter
        int b;          // OK: hides outer variable
    }                   // end of inner block
    int a;              // Error: can't have same name as parameter
}

7
我建议避免混淆“块(block)”和“作用域(scope)”,虽然“内部块的开头”这个注释是正确的,但它省略了一个简洁的细节,即该块引入了一个新的内部“作用域”。说“函数的最外层作用域是定义函数体的块”并不完全正确,相反,定义函数体的块也定义了其最外层作用域。作用域不是块,而是由块定义的。 - davmac
2
@davmac:感谢您的语法批评。我认为措辞已经足够清晰了。 - Mike Seymour
4
@MikeSeymour的批评更注重技术层面而非语法,不过,嘿,那是你的回答。 - davmac

15

这意味着你不能做这样的事情:

void foo (int x)
{
    int x = 4; //in the outermost scope, invalid
}

然而,你可以这样做:

void foo (int x)
{
    { //this introduces a new scope
        int x = 4; //not in the outermost scope, valid
    }
}

5
@dwcanillas 在这个简单的例子中不需要考虑,但在涉及循环或if语句引入作用域的更复杂的例子中,我相信你可以找到一个合理的情况。然而,通常最好避免“重载”变量名称。 - TartanLlama
3
如果你觉得这是一个好主意,那么你的函数很可能过长或过于复杂。 - Baum mit Augen

7
这意味着这是无效的:
void f(int p)
{
   int p = 3;
}

然而这个

void f(int p)
{
  {
    int p = 3;
  }
}

是被允许的。


4

这个规则不仅适用于函数定义的函数参数,还适用于迭代和条件语句以及异常处理程序。

3.3.3 块作用域

2 函数参数名称(包括出现在lambda-declarator中的参数名称)或函数定义(8.4)中的函数本地预定义变量的潜在作用域始于其声明点。如果函数有function-try-block,则参数或函数本地预定义变量的潜在作用域在最后一个相关处理程序的末尾结束;否则,在函数定义的最外层块的末尾结束。函数参数名称不得在函数定义的最外层块或与function-try-block关联的任何处理程序的最外层块中重新声明。

3 在exception-declaration中声明的名称局部于处理程序,不得在处理程序的最外层块中重新声明。

4 在for-init-statement、for-range-declaration和if、while、for和switch语句的条件中声明的名称局部于if、while、for或switch语句(包括受控语句),不得在该语句的后续条件中或受控语句的最外层块(对于if语句,是任何最外层块)中重新声明;请参见6.4。

例如,此代码片段无效。

if( int x = SomeFunction() )
{
    int x; // invalid declaration
    //...
}

2
假设你有一个名为 'foo' 的函数,它接受一个整数参数 'bar'。
int foo (int bar)
{
    int bar = 0; // < illegal, this is the 'outermost' scope
    if (bar == 10) {
        int bar = 5; // legal (though unadvisable) this 'shadows' the passed-in 'bar'
        return bar;
    }
    return bar;
}

由于传入参数与同一上下文中的变量也有声明(即使语法并不一定清晰),因此 'bar' 的第一个内部声明是非法的。

就像写成这样是不正确的:

int bar;
char bar[10];

由于这两个变量共享相同的作用域。

在上面的foo函数中,bar的第二个声明是合法的(尽管通常是不好的想法),因为它在“if”的内部作用域中声明,因此可以使用。

希望这能帮到您。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接