使用C++;名称空间增加耦合? 我知道C++库应该使用命名空间来避免名字冲突,但是我必须已经: #包括正确的标题(或向前声明我打算使用的类) 按名称使用这些类

使用C++;名称空间增加耦合? 我知道C++库应该使用命名空间来避免名字冲突,但是我必须已经: #包括正确的标题(或向前声明我打算使用的类) 按名称使用这些类,c++,namespaces,decoupling,C++,Namespaces,Decoupling,这两个参数不是推断名称空间传递的相同信息吗。使用名称空间现在引入了第三个参数——完全限定名。如果库的实现发生了变化,那么现在我需要改变三件潜在的事情。根据定义,这不是增加了库代码和我的代码之间的耦合吗 例如,看看Xerces-C:它在命名空间Xerces\u CPP\u命名空间中定义了一个名为Parser的纯虚拟接口。我可以在代码中使用解析器接口,方法是包括适当的头文件,然后使用namespace XERCES\u CPP\u namespace导入名称空间,或者使用XERCES\u CPP\

这两个参数不是推断名称空间传递的相同信息吗。使用名称空间现在引入了第三个参数——完全限定名。如果库的实现发生了变化,那么现在我需要改变三件潜在的事情。根据定义,这不是增加了库代码和我的代码之间的耦合吗


例如,看看Xerces-C:它在命名空间
Xerces\u CPP\u命名空间
中定义了一个名为
Parser
的纯虚拟接口。我可以在代码中使用
解析器
接口,方法是包括适当的头文件,然后使用namespace XERCES\u CPP\u namespace导入名称空间
,或者使用
XERCES\u CPP\u namespace::
前置声明/定义

随着代码的发展,可能需要删除Xerce以使用不同的解析器。纯虚拟接口部分“保护”了我,使我不受库实现变化的影响(如果我使用工厂构建解析器,情况更是如此),但一旦我从Xerces切换到其他东西,我需要梳理我的代码,并使用命名空间XERCES\u CPP\u namespace
XERCES\u CPP\u namespace::Parser
更改所有


我最近重新编译了一个现有的C++项目,把一些现有的有用功能分割成一个库:

foo.h

class Useful;  // Forward Declaration

class Foo
{
public:

    Foo(const Useful& u);
    ...snip...

}
namespace useful {
    class Useful;  // Forward Declaration
}

class Foo
{
public:

    Foo(const useful::Useful& u);
    ...snip...
}
foo.cpp

#include "foo.h"
#include "useful.h" // Useful Library

Foo::Foo(const Useful& u)
{
    ... snip ...
}
#include "foo.h"
#include "useful.h" // Useful Library

using namespace useful;

Foo::Foo(const Useful& u)
{
    ... snip ...
}
当时主要是出于无知(部分是出于懒惰),将
use.lib
的所有功能都放在全局名称空间中

随着
usiver.lib
内容的增加(越来越多的客户端开始使用该功能),决定将所有代码从
usiver.lib
移动到它自己的名称空间
“usiver”

客户端
.cpp
文件很容易修复,只需使用名称空间添加
,非常有用

foo.cpp

#include "foo.h"
#include "useful.h" // Useful Library

Foo::Foo(const Useful& u)
{
    ... snip ...
}
#include "foo.h"
#include "useful.h" // Useful Library

using namespace useful;

Foo::Foo(const Useful& u)
{
    ... snip ...
}
但是
.h
文件确实是劳动密集型文件。而不是通过使用
名称空间来污染全局名称空间
在头文件中,我将现有的转发声明包装在名称空间中:

foo.h

class Useful;  // Forward Declaration

class Foo
{
public:

    Foo(const Useful& u);
    ...snip...

}
namespace useful {
    class Useful;  // Forward Declaration
}

class Foo
{
public:

    Foo(const useful::Useful& u);
    ...snip...
}
有几十个(和几十个)的文件,这最终是一个巨大的痛苦!这本不应该那么困难。很明显,我的设计和/或实现都有问题

虽然我知道库代码应该在它自己的名称空间中,但是如果库代码保留在全局名称空间中,而试着管理
#includes
,会有好处吗

(a) 库中的接口/类/函数

没有比你现在拥有的更多。使用
名称空间
-ed库组件可以帮助您避免名称空间污染

(b) 由命名空间推断的实现细节

为什么??您只需要包含一个标题
有用的.h
。实现应该是隐藏的(并且驻留在
有用的.cpp
中,并且可能以动态库的形式存在)


通过让
使用有用::有用的
声明,您可以有选择地只包含那些您需要从
有用的.h
中包含的类。

如果您有“有用”库的多个实现,那么它们使用同一名称空间的可能性是否相同(如果不在您的控制之下),它是全局名称空间还是有用的名称空间

换句话说,使用命名命名空间而不是全局命名空间与库/实现的“耦合”程度无关


任何一致的库演化策略都应该为API维护相同的名称空间。该实现可以利用对您隐藏的不同名称空间,这些名称空间可能会在不同的实现中发生变化。不确定这是否是“由名称空间推断的实现细节”的意思。

不,您没有增加耦合。正如其他人所说,我不认为名称空间的使用会泄露实现

消费者可以选择这样做

 using useful;
 using useful::Foo;
 useful::Foo = new useful::Foo();
我总是投最后一张票——那是污染最少的


(行刑队)应该强烈反对使用第一个名称空间。名称空间与耦合无关。无论您称之为
有用::UsefulClass
还是仅称之为
UsefulClass
,都存在相同的耦合。现在,您需要进行所有重构工作的事实只告诉您代码在多大程度上依赖于您的库

为了简化转发,您可以编写一个
forward
头(STL中有几个,您肯定可以在库中找到它),比如
usefulfwd.h
,它只向前定义库接口(或实现类或任何您需要的)。但这与耦合无关


尽管如此,耦合和名称空间还是不相关的。玫瑰的气味对任何其他名称都一样甜美,而您的类在任何其他名称空间中都是耦合的。

在我看来,您的问题主要是由于您(ab)如何使用名称空间,而不是由于名称空间本身

  • 这听起来像是你在一个名称空间中扔了很多与之相关的“东西”,主要是因为它们碰巧是由同一个人开发的。至少在我看来,名称空间应该反映代码的逻辑组织,而不仅仅是一堆实用程序碰巧由同一个人编写

  • 名称空间名称通常应该相当长且具有描述性,以防止出现超出最远可能的colli