我知道 C++ 库应该使用命名空间来避免名称冲突,但是因为我已经必须:
#include
正确的标题(或转发声明我打算使用的类)- 按名称使用这些类
不要这两个参数推断命名空间传达的相同信息。使用命名空间现在引入了第三个参数 - 完全限定名称。如果库的实现发生变化,现在我需要改变三个潜在的事情。根据定义,这不是增加库代码和我的代码之间的耦合吗?
例如,看一下 Xerces-C:它定义了一个Parser
在命名空间内调用的纯虚拟接口XERCES_CPP_NAMESPACE
。我可以Parser
通过包含适当的头文件,然后导入命名空间using namespace XERCES_CPP_NAMESPACE
或在声明/定义前面加上XERCES_CPP_NAMESPACE::
.
随着代码的发展,可能需要放弃 Xerces 以支持不同的解析器。纯虚拟接口对库实现的更改部分“保护”了我(如果我使用工厂构造我的解析器更是如此),但是一旦我从 Xerces 切换到其他东西,我需要梳理我的代码并更改我的所有using namespace XERCES_CPP_NAMESPACE
代码XERCES_CPP_NAMESPACE::Parser
。
我最近在重构一个现有的 C++ 项目以将一些现有的有用功能拆分到一个库中时遇到了这个问题:
foo.h
class Useful; // Forward Declaration
class Foo
{
public:
Foo(const Useful& u);
...snip...
}
foo.cpp
#include "foo.h"
#include "useful.h" // Useful Library
Foo::Foo(const Useful& u)
{
... snip ...
}
当时很大程度上出于无知(部分出于懒惰),所有的功能useful.lib
都放在了全局命名空间中。
随着内容的useful.lib
增长(以及更多的客户开始使用该功能),决定将所有代码从useful.lib
它自己的命名空间移动到名为"useful"
.
客户端.cpp
文件很容易修复,只需添加一个using namespace useful
;
foo.cpp
#include "foo.h"
#include "useful.h" // Useful Library
using namespace useful;
Foo::Foo(const Useful& u)
{
... snip ...
}
但是这些.h
文件确实是劳动密集型的。我没有通过放入头文件来污染全局命名空间,而是using namespace useful;
将现有的前向声明包装在命名空间中:
foo.h
namespace useful {
class Useful; // Forward Declaration
}
class Foo
{
public:
Foo(const useful::Useful& u);
...snip...
}
有几十个(和几十个)文件,这最终成为一个巨大的痛苦!它不应该那么困难。显然我在设计和/或实现方面做错了。
尽管我知道库代码应该在其自己的命名空间中,但将库代码保留在全局命名空间中是否有利,而不是尝试管理#includes
?