提问人:marcv81 提问时间:12/7/2015 最后编辑:curiousguymarcv81 更新时间:12/7/2015 访问量:6398
“使用命名空间”到底有什么作用?
What does "using namespace" do exactly?
问:
以下 C++ 测试代码未链接(gcc 4.9.2,binutils 2.25)。错误是 。In function 'main': undefined reference to 'X::test'
01: #include <string>
02: #include <iostream>
03:
04: namespace X
05: {
06: extern std::string test;
07: };
08:
09: using namespace X;
10: std::string test = "Test";
11:
12: int main()
13: {
14: std::cout << X::test << std::endl;
15: }
由于第 09 行,我期望第 10 行定义在第 06 行声明的变量。我相信相反,在全局命名空间中声明和定义了一个不相关的变量,因此出现了链接错误。X::test
test
问题:谁能解释一下为什么我的期望不正确,以及到底发生了什么?
不是答案:
- 我可以将第 10 行更改为 .
std::string X::test = "Test";
- 我不应该一开始就使用“使用命名空间”。
答:
using namespace
意味着您使用您指定的命名空间中的定义,但这并不意味着您定义的所有内容都在您使用的命名空间中定义。
这种行为的逻辑非常简单。假设我们有以下示例:
namespace X
{
extern string test;
};
namespace Y
{
extern string test;
};
using namespace X;
using namespace Y;
string test = "value";
按照您的示例逻辑,编译器只是不知道它应该在哪个命名空间中定义,因此您必须显式声明命名空间。在现实生活中,它是在全局命名空间中定义的。test
在特定情况下,您可以在命名空间之外定义变量,该变量声明为 。链接器查找 的定义,但找不到,因此您会看到此错误。test
X
extern
X::test
评论
::test
std::string test = ...
test
using namespace ...
X::
using namespace X;
namespace short = very::long::namespace;
short::identifier
using namespace
X::
using
该指令使命名空间中的名称在包含该指令的命名空间内可见。也就是说,在该范围内查找名称时,可以找到。但是,只有当编译器需要查找它时,才会查找它。using namespace X;
X
n
X::n
在您的示例中,以下声明:
std::string test = "Test";
在全局命名空间内是完全有意义的。与任何其他声明一样,该名称只是简单地介绍。无需在任何地方查找。test
这将是一锅完全不同的鱼:
namespace X
{
struct C
{
static std::string test;
};
}
using namespace X;
std::string C::test = "Test";
在此代码中,编译器需要知道什么是有意义的定义。因此,它对 进行名称查找,这确实要归功于该指令。C
C::test
C
X::C
using
评论
这是命名空间中变量的声明。test
X
04: namespace X
05: {
06: extern std::string test;
07: };
它不是变量的定义。还必须先定义该变量,然后才能使用它来获取其值。
如果初始化变量,也可以将此声明作为定义。例如
04: namespace X
05: {
06: extern std::string test = "Test";
07: };
在这种情况下,代码将成功编译。
在此声明中
14: std::cout << X::test << std::endl;
可以访问限定名称 。编译器在变量中指定的命名空间中搜索此名称,并查找声明。现在它需要获取变量的值,但它无法找到它的定义。X::test
X
在此声明中
10: std::string test = "Test";
全局命名空间中存在声明和定义的变量,因为它是在任何显式指定的命名空间之外声明的。test
你可以写
10: std::string X::test = "Test";
^^^^^^^
而不是
10: std::string test = "Test";
如果要定义在命名空间中声明的变量。X
至于 using 指令,它会在使用该指令的命名空间中引入在指定命名空间中声明的名称。
例如,如果使用非限定名称进行写入test
14: std::cout << test << std::endl;
^^^^^
然后就会有歧义,因为这个名称可以引用名称,并且由于 using 指令。X::test
::test
评论
extern
Undefined reference
extern