在全局作用域和局部作用域中,为什么使用指令的行为不同?

13
当我写下以下代码时,它可以被正确地编译和执行:
#include <iostream>
using namespace std;

namespace first
{
  int x = 5;
  int y = 10;
}

namespace second
{
  double x = 3.1416;
  double y = 2.7183;
}

int main () {
  using namespace first; //using derective
  using second::y;
  cout << x << endl;
  cout << y << endl;
  return 0;
}

但如果我像下面这样在主函数外使用指令:

using namespace first; //using derective
using second::y;
int main () {
  cout << x << endl;
  cout << y << endl;
  return 0;
}

它会产生这个编译错误:

g++     namespace03.cpp   -o namespace03
namespace03.cpp: In function ‘int main()’:
namespace03.cpp:20:11: error: reference to ‘y’ is ambiguous
namespace03.cpp:13:10: error: candidates are: double second::y
namespace03.cpp:7:7: error:                 int first::y
make: *** [namespace03] Error 1

能否有人解释一下,为什么在main内和main外使用编译指示符会有不同的行为?

2个回答

12
< p>using声明只是一个声明。在main函数内部使用using second::y;类似于在该范围内声明变量y,它会隐藏全局命名空间范围内的任何其他y。在全局范围内使用using second::y;时,您没有隐藏任何名称,因为两个y都在同一作用域中。

想象一下,你的第一个例子就像下面这样(请参见下面的注释进行说明):

namespace first
{
  int x = 5;
  int y = 10;
}

int main () {
  using namespace first; // This makes first::y visible hereafter
  int y = 20; // This hides first::y (similar to using second::y)
  cout << x << endl;
  cout << y << endl; // Prints 20 
}

然而,第二个例子是这样的:

namespace first
{
  int x = 5;
  int y = 10;
}
using namespace first; // This makes first::y visible in global scope
int y = 20; // This is global ::y
int main () {
  cout << x << endl;
  cout << y << endl; // Error! Do you mean ::y or first::y?
}

1
谢谢Jesse的快速回复...如果我错了,请纠正我...但是,即使在主函数中使用指令,仍然会有两个y的声明。如果是这样,为什么编译器只在第二种情况下出现问题? - Amrit
2
@user2235938:y有两个声明,但是using-declaration在main函数内声明了second::y,而first::y则在全局命名空间范围内声明。由于second::y在main函数内声明,它会隐藏first::y。你是否熟悉名称隐藏? - Jesse Good
抱歉Jesse...但我无法理解。当语句"using namespace first; using second::y;"都在main函数内部时,它应该在本地作用域中声明first::y和second::y并产生编译错误。但实际上它没有,程序可以成功编译和运行。而当这两个语句都在main函数外部时,由于二义性,甚至无法编译。请解释一下... - Amrit
@user2235938:我试着用一个例子来解释。这里的重要部分是 using second::y 隐藏了 first::y。就像在不同作用域中声明两个同名变量一样,内部作用域中声明的变量会隐藏外部作用域中的变量。 - Jesse Good
@user2235938,看一下我的回答,它可能会回答你的问题。 - AlexDan
@Jesse和Alex:非常感谢你们提供如此好的解释和友善。 - Amrit

7
使用声明(using-declaration)和使用指令(using-directive)之间有两个主要的不同之处。 第一个不同点:(显而易见的不同点)。
namespace first{
 
int x=1;
int y=2;
}
using first::x; //using declaration

这将允许你使用变量x而不需要命名空间名称作为显式限定符,注意这不包括y
namespace first{
int x=1;
int y=2;
}
using namespace first;// using directive

这将允许您在命名空间first中使用所有变量,而无需使用namespace-name作为显式限定符。


第二个区别:(这就是你不理解的东西)。

我将向您解释为什么当您在主函数中同时使用using-directive和using-declaration时,您不会出现错误,但是当您尝试在全局命名空间中同时使用它们时,会出现编译时错误。

假设我们在全局命名空间中定义了两个命名空间,如下所示:

namespace first
{
  int x = 5;
  int y = 10;
}

namespace second
{
  double x = 3.1416;
  double y = 2.7183;
}

Example 1:
int main () {    
using namespace first;
using second::y;
  cout << x << endl; // this will output first::x;
  cout << y << endl; // this will output second::y;
  return 0;
}

原因是 using-declaration using second::y 会使得你的变量y 看起来像是在使用该声明的作用域中的局部变量,而此处它被用在了主函数内。而 using-directive using namespace first 将会使得在该命名空间 first 中定义的变量看起来像是全局变量,在该指令所使用的作用域内有效,此处是在主函数内。
因此,如果你按照上述所说去做,那么你就会知道如果你这样做了:

示例2:

 using namespace first;
 using second::y;

 int main () {    
  cout << x << endl; 
  cout << y << endl; // two definitions of y. first::y and second::y 
  return 0;
}

由于first::ysecond::y都会像在全局命名空间中定义一样行事,因此您将会收到一个错误,这将违反一个定义规则。


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