简体   繁体   English

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

[英]Why is including “using namespace” into a header file a bad idea in C++?

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). 但是,您几乎从未在头文件中看到using指令(至少不在范围之外)。 The reason is that using directive eliminate the protection of that particular namespace, and the effect last until the end of current compilation unit. 原因是using指令消除了对该特定命名空间的保护,并且效果持续到当前编译单元结束。 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指令(在作用域之外),则意味着在包含此头文件的任何文件中都会发生“名称空间保护”丢失,这通常意味着其他头文件。

Would you please like to help me to comprehend the above statement with some easy example? 您是否愿意用一些简单的例子来帮助我理解上述陈述?

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; 这里的问题是当main()指定string x; , the compiler's not sure whether the user-defined ::string or included std::string is wanted. ,编译器不确定是否需要用户定义的::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 #include before main() . 现在想象一下你从程序的顶部开始......第1行到第5行 - 包括struct string ......然后把它放到一个头文件中,然后在main()之前#include Nothing changes: you still have an error. 没有任何变化:你仍然有错误。 So, just as for standalone programs, header files with using statements in them can cause trouble for other code that includes them, making some of their statements ambiguous. 因此,就像独立程序一样,带有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 using statement from the header, or 从标题中删除using语句,或
  • a change to the contents of <string> , or any other header affecting std:: 更改<string>的内容,或影响std::任何其他标头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 using statement may not have filesystem/code-repository permissions, corporate authority etc. to remove the using statement 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 ::的更改的潜在影响会大大减少。

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 std function/class in the global namespace in any of those modules. 这意味着您永远不能在任何这些模块的全局命名空间中声明函数或定义具有相同名称(以及函数的兼容参数)的类作为std函数/类。

Copy the following paragraph from "C++ Primer, fifth edition": 复制“C ++ Primer,第五版”中的以下段落:

Code inside headers ordinarily should not use using declarations. 标题内的代码通常不应using声明。 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. 如果标头具有using声明,那么包含该标头的每个程序都会使用声明获得相同的结果。 As a result, a program that didn't intent to use the specified library name might encounter unexpected name conflicts. 因此,不打算使用指定库名的程序可能会遇到意外的名称冲突。

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. 假设您有一些非常常见的类名,例如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). 如果使用多个库,则存在库A中的FooBar与库B中的FooBar冲突的风险。为此,我们使用两个不同的命名空间A和B,将FooBars从全局命名空间移动到A :: FooBar和B :: FooBar (所以他们彼此分开)。

If you then put using A; 如果你再using A; and using B; 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. 在标题中,这将把A :: FooBar和B :: FooBar移动到FooBar,带回冲突,从一开始就消除使用命名空间的收益。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM