"using namespace"到底是做什么的?
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 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
指令。
using namespace
表示您使用指定命名空间中的定义,但这并不意味着您定义的所有内容都在您使用的命名空间中定义。
这种行为的逻辑非常简单。假设我们有以下示例:
namespace X
{
extern string test;
};
namespace Y
{
extern string test;
};
using namespace X;
using namespace Y;
string test = "value";
按照您的示例逻辑,编译器只是不知道它应该在哪个命名空间中定义test
,因此您必须显式声明命名空间。在现实生活中,它是在全局命名空间中定义的。
在您的特定情况下,您可以在 X
命名空间之外定义 test
变量,在该命名空间中,该变量被声明为 extern
。链接器查找X::test
的定义,但找不到,因此您会看到此错误。
这是命名空间X
中变量test
的声明。
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;
^^^^^
那么就会有歧义,因为这个名称可以指名称X::test
,并且由于 using 指令而::test
。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 警告处理为错误这里有什么问题
- 什么时候调用组成单元对象的析构函数
- "using namespace std;"在C++的作用是什么?
- C++中"typedef"、"using"、"namespace"和"using namespace"有什么区别?
- C++ "using tcp=x"到"namespace tcp=x"有什么区别
- "using namespace"子句在什么范围内有效?
- 引用 using 声明引入的功能的句子是什么意思?
- 附加包含目录和其他 #using 目录有什么区别?
- "using X = int(&)()"做什么?
- "using"关键字在 c++ 中究竟有什么作用?
- C++中"using"关键字背后的逻辑是什么?
- 模板类型定义的新"using"语法解决了什么问题?
- "using namespace"到底是做什么的?
- 什么是“using”,以及C++中构造函数后面的冒号是什么
- "using"命名空间和声明命名空间有什么区别?
- typedef和using之间有什么区别?
- c++中using和include的区别是什么?
- C++中的"using var_name = data_type;"是什么意思?
- 什么是"template<class T> using owner = T;"?