【问题标题】:In C++, when can two variables of the same name be visible in the same scope?在 C++ 中,两个同名变量何时可以在同一范围内可见?
【发布时间】:2009-06-06 00:07:13
【问题描述】:

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

#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++ 警告我呢?其他编译器是否对此嗤之以鼻?

【问题讨论】:

    标签: c++ standards warnings compiler-warnings


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      这是完全有效的,但我认为使用-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 中。

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

          【解决方案4】:

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

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

          #include  <iostream>
          
          
          int a = 5;
          int main()
          {
              int a = 6;
          
              std::cout << a << "\n" << ::a << "\n";
                      // Local
                                     // global
          }
          

          【讨论】:

          • “所有语言都允许这种事情”。我的 TI-85 计算器上的编程语言没有。所有变量都是全局的,没有名字隐藏。
          • .NET (VB, C#) 也不允许这样做!
          • 当我使用高阶函数时,C# 对阴影的禁令让我非常恼火。
          • 据我所知,BASIC 语言(VB,内置 TI 程序)没有真正的范围定义,这就是为什么不允许阴影。
          【解决方案5】:

          在允许的情况下回答:基本上在任何两个嵌套范围内。

          例如:

          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.
          

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

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

          【讨论】:

            【解决方案6】:

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

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

            【讨论】:

              猜你喜欢
              • 2018-09-17
              • 1970-01-01
              • 2017-10-07
              • 1970-01-01
              • 1970-01-01
              • 2021-06-23
              • 1970-01-01
              • 2020-08-01
              • 1970-01-01
              相关资源
              最近更新 更多