我真的不明白翻译单元是什么以及如何使用未命名的命名空间:
如果我有一个.cpp文件:
namespace
{
void extFunction()
{
std::cout << "Called Unnamed Namespace's function.\n";
}
}
和一个主.cpp文件:
#include <iostream>
#include "ext.cpp"
using namespace std;
int main()
{
extFunction();
return 0;
}
为什么我可以从另一个文件访问未命名的命名空间的成员?
编辑:
谢谢你的回复;但是,我如何使用未命名的命名空间,以及用于什么目的?
翻译单元基本上是您为编译器处理的代码块。编译器处理它并为链接器生成目标代码。链接器将来自所有翻译单元的目标代码组合在一起以形成可执行文件。 (有时您会看到与此不同的详细信息,例如,当您只有一个翻译单元时,没有看到目标代码的文件。即使实施细节可能有所不同,该概念仍然有效。)
通常,在编译和翻译单元时生成的.o
(或.obj
)文件之间存在一对一的对应关系。通常,您为每个.o
文件获取一个.cpp
文件。因此,将每个.cpp
文件视为其自己的翻译单元通常是合理的。直到你做一些非常规的事情。
当您使用#include
指令时,您告诉编译器将该行替换为所包含文件的全部内容。也就是说,给予编译器的代码块包括来自原始文件和包含文件的代码。如果将一个.cpp
文件包含到另一个文件中,则给编译器的代码块将包含两个.cpp
文件中的代码,从而打破了.cpp
文件和翻译单元之间的等效性。这通常被认为是一个坏主意。
我们来看一个例子。假设您有一个名为ext.cpp
的文件,其中包含以下内容:
namespace
{
void extFunction()
{
std::cout << "Called Unnamed Namespace's function.\n";
}
}
还假设您有一个名为main.cpp
的文件,其中包含以下内容:
#include <iostream>
#include "ext.cpp"
int main()
{
extFunction();
return 0;
}
如果您要编译main.cpp
,编译器将要做的第一件事就是预处理main.cpp
。这会修改文件的内容,改变编译器看到的内容。在预处理之后,编译器将处理的代码块如下所示。
[lots of code from the library header named "iostream"]
namespace
{
void extFunction()
{
std::cout << "Called Unnamed Namespace's function.\n";
}
}
int main()
{
extFunction();
return 0;
}
此时,调用extFunction
没有问题,因为编译器在它正在处理的代码块中看到了未命名的命名空间。
有关使用未命名命名空间的请求信息的另一个示例。与上述类似,但不同。假设您有一个名为ext.cpp
的文件,其中包含以下内容:
#include <iostream>
namespace
{
void extFunction()
{
std::cout << "Called Unnamed Namespace's function in EXT.\n";
}
}
void extPublic()
{
extFunction();
}
我们还提供一个标题(ext.h
),它将声明具有外部链接的函数。
void extPublic();
现在转到main.cpp
:
#include <iostream>
#include "ext.h" // <-- Including the header, not the source.
namespace
{
void extFunction()
{
std::cout << "Called Unnamed Namespace's function in MAIN.\n";
}
}
int main()
{
extFunction();
extPublic();
return 0;
}
看那个!名为extFunction
的函数有两个定义!链接器不会混淆吗?一点也不。这些功能在翻译单元之外是看不到的,所以没有冲突。如果你编译main.cpp
,编译ext.cpp
,并将main.o
和ext.o
链接到一个可执行文件,你会得到以下输出。
在MAIN中调用未命名的命名空间的功能。 在EXT中调用未命名的命名空间的功能。
未命名的命名空间的一个好处是您不必担心与另一个源文件的未命名命名空间中的名称冲突。 (当您的项目增长到包含数百个源文件时,这会带来更大的好处。)