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

时间:2011-02-02 08:50:26

标签: c++ namespaces global-namespace

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

  

然而,你几乎从未见过   在头文件中使用指令   (至少不在范围之外)。该   原因是使用指令   消除对此的保护   特定的命名空间,以及效果   持续到当前结束   编译单位。如果你使用   a中的指令(在范围之外)   头文件,就意味着这种损失   “命名空间保护”将在其中发生   任何包含此文件的文件   标题,通常表示其他标题   文件。

请您帮我用一些简单的例子来理解上述陈述吗?

4 个答案:

答案 0 :(得分:30)

考虑这个程序:

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 }

如果您尝试编译它,您将看到错误:

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"

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

现在假设你占据了程序的顶部......第1行到第5行 - 包括struct string ...并将其放入头文件中,然后再#include main()。没有任何变化:你仍然有错误。因此,就像独立程序一样,其中包含using语句的头文件可能会给包含它们的其他代码带来麻烦,使得它们的一些语句不明确。

但这可能是一个更大的痛苦,因为标题可以直接或间接地包含在任意大量的依赖代码中,并且... ...

  • 从标题中删除using语句,或
  • <string>或任何其他影响std::
  • 的标题内容的更改

...可能会破坏包含有问题标题的代码。任何一个问题都可能使相关代码无法编译,甚至在尝试进行另一次编译之前甚至都不会发现问题。此外,由于using语句而受到影响的人可能没有文件系统/代码库权限,公司权限等从标头中删除using语句,也无法修复其他受影响的客户端代码。

也就是说,如果一个头只在一个类或函数中有“使用”,那么对该范围之外的代码没有任何影响,因此对std ::的更改的潜在影响会大大减少。

答案 1 :(得分:16)

如果标头包含using namespace std,那么来自该命名空间的所有内容都会在包含标头的每个模块中添加全局命名空间。

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

答案 2 :(得分:5)

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

  

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

答案 3 :(得分:4)

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

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

如果然后将using A;using B;放入标题中,则会将A :: FooBar和B :: FooBar移动到FooBar,从而恢复冲突,从中删除使用命名空间的增益第一名。