为什么在 C++ 中将“使用命名空间”包含到头文件中是个坏主意?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4872373/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:49:06  来源:igfitidea点击:

Why is including "using namespace" into a header file a bad idea in C++?

c++namespacesglobal-namespace

提问by user388338

While reading from Bruce Eckel's "Thinking in C++" about namespaces, I encountered the following statement:

在阅读 Bruce Eckel 关于命名空间的“Thinking in C++”时,我遇到了以下语句:

However you'll virtually never see a using directive in a header file (at least not outside of scope). The reason is that using directive eliminate the protection of that particular namespace, and the effect last until the end of current compilation unit. If you put a using directive (outside of a scope) in a header file, it means that this loss of "namespace protection" will occur within any file that include this header, which often mean other header files.

但是,您几乎永远不会在头文件中看到 using 指令(至少不在范围之外)。原因是 using 指令消除了对该特定命名空间的保护,并且效果持续到当前编译单元结束。如果将 using 指令(在作用域之外)放在头文件中,则意味着在包含此头文件的任何文件中都会发生这种“命名空间保护”的丢失,这通常意味着其他头文件。

Would you please like to help me to comprehend the above statement with some easy example?

你愿意用一些简单的例子帮助我理解上面的陈述吗?

回答by Tony Delroy

Consider this program:

考虑这个程序:

line#
    1 #include <string>                                                               
    2                                                                                 
    3 using namespace std;                                                            
    4                                                                                 
    5 struct string { const char* p; };  // Beware: another string!
    6                                                                                 
    7 int main()                                                                      
    8 {                                                                               
    9     string x; // Error: ambiguous - which string is wanted?
   10 }

If you try to compile it, you'll see errors:

如果你尝试编译它,你会看到错误:

g++     using.cc   -o using
using.cc: In function `int main()':
using.cc:9: error: use of `string' is ambiguous
using.cc:5: error:   first declared as `struct string' here
/usr/lib/gcc/i386-redhat-linux/3.4.6/../../../../include/c++/3.4.6/bits/stringfwd.h:60: error:
   also declared as `typedef struct std::basic_string<char, std::char_traits<char>, std::allocator<char> > std::string' here
using.cc:9: error: `string' was not declared in this scope
using.cc:9: error: expected `;' before "x"

The problem here is that when main()specifies string x;, the compiler's not sure whether the user-defined ::stringor included std::stringis wanted.

这里的问题是,当main()指定时string x;,编译器不确定是否需要用户定义::string或包含std::string

Now imagine you take the top part of the program... lines 1 through 5 - up to and including the struct string... and put it into a header file which you then #includebefore main(). Nothing changes: you still have an error. So, just as for standalone programs, header files with usingstatements in them can cause trouble for other code that includes them, making some of their statements ambiguous.

现在假设您将程序的顶部...第 1 行到第 5 行 - 直到并包括struct string... 并将其放入头文件中,然后#includemain(). 没有任何变化:您仍然有错误。因此,就像对于独立程序一样,其中包含using语句的头文件可能会给包含它们的其他代码带来麻烦,从而使它们的某些语句变得模棱两可。

It can be a bigger pain though, as headers can be included - directly or indirectly - by arbitrarily huge amounts of dependent code, and...

但是,这可能会带来更大的痛苦,因为可以通过任意大量的依赖代码直接或间接地包含标头,并且...

  • removing the usingstatement from the header, or
  • a change to the contents of <string>, or any other header affecting std::
  • using从标题中删除语句,或
  • 的内容更改<string>,或任何其他影响std::

...might break code including the problematic header. Either problem may render dependent code uncompilable, and issues may not even be noticed until another compilation is attempted. Further, the person suffering due to the usingstatement may not have filesystem/code-repository permissions, corporate authority etc. to remove the usingstatement from the header, nor fix other affected client code.

...可能会破坏代码,包括有问题的标题。任何一个问题都可能导致相关代码无法编译,并且在尝试另一次编译之前甚至可能不会注意到问题。此外,由于该using语句而遭受痛苦的人可能没有文件系统/代码存储库权限、公司权限等,无法using从标题中删除该语句,也没有修复其他受影响的客户端代码。

That said, if a header only has "using" inside a class or function, then there's no affect on code beyond that scope, so the potential impact of changes to std:: is dramatically reduced.

也就是说,如果头文件只在类或函数内部“使用”,那么对超出该范围的代码没有影响,因此对 std:: 更改的潜在影响显着减少。

回答by Fred Foo

If a header contains using namespace std, everything from that namespace is added the global namespace in every module that includes the header.

如果标头包含using namespace std,则该命名空间中的所有内容都将添加到包含标头的每个模块中的全局命名空间。

This means you can never declare a function or define a class with the same name (and compatible parameters for a function) as an stdfunction/class in the global namespace in any of those modules.

这意味着您永远不能std在任何这些模块的全局命名空间中声明一个函数或定义一个与函数/类具有相同名称(和函数的兼容参数)的类。

回答by Shen

Copy the following paragraph from "C++ Primer, fifth edition":

从“C++ 入门,第五版”中复制以下段落:

Code inside headers ordinarily should not use usingdeclarations. The reason is that the contents of a header are copied into the including program's text. If a header has a using declaration, then every program that includes that header gets that same using declaration. As a result, a program that didn't intent to use the specified library name might encounter unexpected name conflicts.

标头内的代码通常不应使用using声明。原因是标题的内容被复制到包含程序的文本中。如果头文件有 using 声明,则包含该头文件的每个程序都会获得相同的 using 声明。因此,无意使用指定库名称的程序可能会遇到意外的名称冲突。

回答by Johan Kotlinski

Well, what is the point of using namespaces. It is to avoid the risk of name collisions.

那么,使用命名空间有什么意义呢?这是为了避免名称冲突的风险。

Let's say that you have some pretty common class name, for example FooBar. If you use several libraries, there is the risk that FooBar in library A collides with FooBar in library B. For that we use two different namespaces A and B, to move the FooBars from global namespace to A::FooBar and B::FooBar (so they are kept separate from each other).

假设您有一些非常常见的类名,例如 FooBar。如果您使用多个库,则存在库 A 中的 FooBar 与库 B 中的 FooBar 冲突的风险。为此,我们使用两个不同的命名空间 A 和 B,将 FooBar 从全局命名空间移动到 A::FooBar 和 B::FooBar (因此它们彼此分开)。

If you then put using A;and using B;in headers, this will then move A::FooBar and B::FooBar to just FooBar, bringing back the collision, removing the gain from using namespaces in the first place.

如果您随后放入using A;using B;放入标头,这会将 A::FooBar 和 B::FooBar 移动到仅 FooBar,从而恢复碰撞,首先消除使用命名空间的好处。