6

这段代码说明了一些我认为应该被视为不好的做法,并引发编译器关于重新定义或屏蔽变量的警告:

#include <iostream>

int *a;

int* f()
{
  int *a = new int;
  return a;
}

int main()
{
  std::cout << a << std::endl << f() << std::endl;
  return 0;
}

它的输出(用 g++ 编译):

0
0x602010

我查看了一些参考资料(Stroustrup 和 The Complete C++ Reference),但找不到任何关于何时以及为何允许这样做的信息。不过,我知道它不在一个本地范围内。

何时以及为何允许这样做?这个结构有什么好的用途吗?我怎样才能让 g++ 警告我呢?其他编译器是否对此大喊大叫?

4

6 回答 6

15

至于为什么允许这样做:这是完全有效的。

当您在 f() 函数中时,您正在定义一个本地范围。局部范围覆盖全局范围,因此在此处定义“a”变量会“隐藏”全局int *a;

于 2009-06-06T00:16:11.843 回答
10

这是完全有效的,但我认为-Wall只有在隐藏参数时才会收到警告。

如果您在隐藏任何类型的变量时需要警告,您可以从g++手册页中使用它:

   -Wshadow
       Warn whenever a local variable shadows another local variable, 
       parameter or global variable or whenever a built-in function is 
       shadowed.

请注意,默认情况下-Wshadow不包括在内-Wall

于 2009-06-06T00:17:22.043 回答
6

允许这样做,以便您可以安全地忽略全局标识符覆盖。本质上,您只需要关心您实际使用的全局名称。

假设,在您的示例中,f()已首先定义。然后其他一些开发人员添加了全局声明。通过添加一个f()曾经有效的名称,现在仍然有效。如果覆盖是一个错误,那么该函数将突然停止工作,即使它对新添加的全局变量根本没有做任何事情。

于 2009-06-06T00:19:01.167 回答
4

很多语言都允许这种事情。
通常(与所有语言相关)最本地定义的变量也是您所指的变量。在我使用的 20 多种语言中,这种语言很常见。

此外,大多数语言都允许您明确引用外部范围内的语言。
例如,C++ 允许您使用 :: 运算符在全局范围内指定变量。

#include  <iostream>


int a = 5;
int main()
{
    int a = 6;

    std::cout << a << "\n" << ::a << "\n";
            // Local
                           // global
}
于 2009-06-06T00:17:06.817 回答
1

回答何时允许这样做:基本上在任何两个嵌套范围内。

例如:

void foo() {
    int a;
    {
        int a;
    }
}

class Base {
    int a;
};
class Derived: public Base {
    int a; // Yes, the name Base::a is visible in the scope of Derived, even if private
};

class Foo() {
    int a;
    Foo(int a) : a(a) { } // Works OK
};

using std::swap;
void swap(MyClass& lhs, MyClass& rhs);
// Not strictly a variable, but name lookup in C++ happens before determining 
// what the name means.

现在,答案肯定是通常允许在同一范围内拥有两个具有同一个名称的“事物”。这是可能的,因为最多有一个名称实际上是在该范围内定义的;其他人将仅在该范围内可见。如果有多个候选者,名称解析规则确定选择哪个名称。

您真的不想对编译器在备选方案之间进行选择的每种情况发出警告。这会给你很多警告,比如重载和一些智能模板代码。

于 2009-06-08T09:14:15.400 回答
0

正如其他人所提到的,这是完全合法的,并且对编译器来说是明确的。

但是,它是编程语言中的众多功能之一,可能会导致混淆或难以发现的错误。由于为这些变量中的每一个赋予不同的名称是微不足道的,为了清楚起见,我总是建议这样做。

于 2009-06-06T14:55:21.003 回答