这段代码说明了一些我认为应该被视为不良做法的内容,并引发编译器关于重新定义或屏蔽变量的警告:
#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 ++警告我呢?其他编译器是否会喋喋不休?
答案 0 :(得分:15)
至于为什么允许这样做:这是完全有效的。
当你在f()函数中时,你正在定义一个局部范围。本地范围覆盖全局范围,因此定义“a”变量会“隐藏”全局int *a;
答案 1 :(得分:9)
这是完全有效的,但我认为使用-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
。
答案 2 :(得分:6)
允许您可以安全地忽略全局标识符覆盖。从本质上讲,您只需要关注实际使用的全局名称。
假设在您的示例中,首先定义了f()
。然后其他一些开发者添加了全局声明。通过添加曾经工作的f()
名称仍然有效。如果覆盖是一个错误,那么该函数会突然停止工作,即使它对新添加的全局变量没有任何作用。
答案 3 :(得分:4)
许多语言允许这种事情 通常(与所有语言相关),最本地定义的变量也是您所指的变量。在我使用的20多种语言中,这很常见。
此外,大多数语言都允许您明确引用外部范围中的语言 例如,C ++允许您使用:: operator。
在全局范围内指定变量#include <iostream>
int a = 5;
int main()
{
int a = 6;
std::cout << a << "\n" << ::a << "\n";
// Local
// global
}
答案 4 :(得分: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.
现在,答案必须明确是通常允许在同一范围内使用单个名称的两个“事物”。这是可能的,因为在该范围内,其中一个名称实际上是定义的;其他人只是在该范围内可见。如果有多个候选者,名称解析规则将确定选择的名称。
您真的不想对编译器在备选方案之间选择的每种情况发出警告。这将为你提供大量的警告,包括重载和一些智能模板代码等无辜的东西。
答案 5 :(得分:0)
正如其他人所提到的,这是完全合法的,并且对编译器来说是明确的。
然而,它是编程语言中的众多功能之一,可能会导致混淆或难以发现的错误。由于为每个变量赋予不同的名称是微不足道的,为了清楚起见,我总是建议这样做。