在我们所有的c ++课程中,所有教师总是将using namespace std;
放在他们#include
文件中的.h
之后。从那时起,我觉得这很危险,因为在另一个程序中包含该标题我会将命名空间导入到我的程序中,可能没有意识到,打算或想要它(标题包含可以非常深层嵌套)。
所以我的问题是双重的:我是对的,using namespace
不应该在头文件中使用,和/或是否有某种方法可以撤消它,例如:
//header.h
using namespace std {
.
.
.
}
同样的问题还有一个问题:头文件#include
应该是所有与其对应.cpp
文件所需的头文件,只需要头文件定义所需的头文件并让{{1} }文件.cpp
其余的,或者没有,并声明它需要的所有内容#include
?
问题背后的原因与上述相同:在包含extern
文件时,我不希望出现意外。
另外,如果我是对的,这是一个常见的错误吗?我的意思是在现实世界的编程和那里的“真实”项目中。
谢谢。
答案 0 :(得分:102)
你绝对不应该在标题中使用using namespace
,正是因为它可以意外地改变包含该标题的任何其他文件中代码的含义。没有办法撤消using namespace
,这是另一个如此危险的原因。我通常只使用grep
等来确保标题中没有调出using namespace
而不是尝试更复杂的内容。可能静态代码检查器也会标记这一点。
标题应该只包含它需要编译的标题。一种简单的方法是在任何其他标头之前始终将每个源文件自己的标头包含在内。如果标头不是自包含的,则源文件将无法编译。在某些情况下,例如,引用库中的实现详细信息类,您可以使用前向声明而不是#include
,因为您可以完全控制此类前向声明的类的定义。
我不确定我会把它称为常见,但它肯定会偶尔出现,通常是由不了解负面后果的新程序员编写的。通常只需要对风险进行一点教育即可解决任何问题,因为修复起来相对简单。
答案 1 :(得分:22)
Sutter和Alexandrescu的“C ++编码标准:101规则,指南和最佳实践”中的第59项:
- 不要在头文件中或#include之前编写命名空间。 108
醇>
所有指南的标题都在http://www.gotw.ca/publications/c++cs.htm,但详细信息是C ++开发人员必读的内容。
答案 2 :(得分:12)
在标题内包含标题时需要小心。在大型项目中,它可以创建一个非常纠结的依赖链,触发比实际需要更大/更长的重建。查看this article和its follow-up,了解有关C ++项目中良好物理结构重要性的更多信息。
在绝对需要时(只要需要完整定义类),您应该只在头部中包含标头,并在任何可能的地方使用前向声明(当需要类是指针或引用时)。
对于名称空间,我倾向于在头文件中使用显式名称空间作用域,并且只在我的cpp文件中放入using namespace
。
答案 3 :(得分:6)
查看戈达德太空飞行中心的编码标准(C和C ++)。结果比过去有点困难 - 请参阅SO问题的更新答案:
GSFC C ++编码标准说:
§3.3.7每个头文件都应
#include
编译所需的文件,而不是强迫用户#include
所需的文件。#includes
应限于标题所需的内容;其他#includes
应放在源文件中。
现在,第一个交叉引用的问题包括GSFC C编码标准的引用和基本原理,但该实质内容最终相同。
答案 4 :(得分:5)
你是对的,标题中的using namespace
是危险的。
我不知道如何撤消它。
它很容易检测到,但只是在头文件中搜索using namespace
。
出于这个最后的原因,它在实际项目中并不常见。如果有人做类似的话,更有经验的同事很快就会抱怨。
在实际项目中,人们会尽量减少所包含文件的数量,因为包含的文件越少,编译得越快。这节省了每个人的时间。但是,如果头文件假定应该在它之前包含某些内容,那么它应该包含它本身。否则它会使标题不是自包含的。
答案 5 :(得分:4)
你是对的。任何文件都应该只包含该文件所需的标头。至于“在现实世界的项目中经常出错吗?” - 哦,是的!
答案 6 :(得分:3)
就像编程中的所有事情一样,实用主义应该胜过教条主义,IMO。
只要你在项目范围内做出决定(“我们的项目广泛使用STL,我们不想在std ::。之前添加所有内容。”),我没有看到它的问题。毕竟,你唯一担心的是名称冲突,而且随着STL的普及,它不太可能成为问题。
另一方面,如果它是一个开发人员在单个(非私有)头文件中的决定,我可以看到它如何在团队中产生混淆,应该避免。
答案 7 :(得分:3)
关于“是否有某种方法撤消[using
声明]?”
我认为指出using
声明受范围影响是有用的。
#include <vector>
{ // begin a new scope with {
using namespace std;
vector myVector; // std::vector is used
} // end the scope with }
vector myOtherVector; // error vector undefined
std::vector mySTDVector // no error std::vector is fully qualified
所以实际上是的。通过限制using
声明的范围,其效果仅在该范围内;当范围结束时,它“撤消”。
当在任何其他范围之外的文件中声明using
声明时,它具有文件范围并影响该文件中的所有内容。
对于头文件,如果using
声明位于文件范围,则这将扩展到包含头的任何文件的范围。
答案 8 :(得分:2)
我相信如果你在一个嵌套的命名空间中编写声明,你可以安全地在C ++标题中使用'using':
namespace DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED
{
/*using statements*/
namespace DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED
{
/*declarations*/
}
}
using namespace DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED::DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED;
这应仅包括在'DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED'中声明的内容,而不使用名称空间。我在mingw64编译器上测试了它。
答案 9 :(得分:0)
您可以通过将头文件包含在块作用域中来保持其“使用”的效果:
//header.h
extern "C++" {
using namespace std; // various 'using' statements ...
// ... declarations ...
}
或者如果您碰巧已经在名称空间中进行了声明:
//header.h
namespace mynamespace {
using namespace othernamespace; // various 'using' statements ...
// ... declarations ...
}
声明块作用域的其他常见方式包括类,结构和联合定义以及内联函数。头文件中“使用”的这种包含用法可以帮助简化声明并提高可读性。