【发布时间】:2010-02-04 19:36:20
【问题描述】:
我了解 C++ 库应该使用命名空间来避免名称冲突,但因为我已经必须:
-
#include正确的标头(或转发声明我打算使用的类) - 按名称使用这些类
不要这两个参数推断一个命名空间传达的相同信息。使用命名空间现在引入了第三个参数 - 完全限定名称。如果库的实现发生变化,现在有 三个 潜在的事情我需要改变。从定义上讲,这不是增加了库代码和我的代码之间的耦合吗?
例如,看一下 Xerces-C:它在命名空间 XERCES_CPP_NAMESPACE 内定义了一个名为 Parser 的纯虚拟接口。我可以在我的代码中使用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 是否有利?
【问题讨论】:
-
"(b) 命名空间推断的实现细节" -- 你能更详细地解释一下吗?我不明白这是什么意思。
-
在我回答这个问题之前我差点睡着了,我还是不太明白你在问什么。您是否考虑过:使用有用的::有用的;
-
那是很多文字。有没有我可以阅读的精简版?
-
@*:阅读倒数第二段。
-
+1:忽略仇恨者。我喜欢读你的帖子!
标签: c++ namespaces decoupling