是否有一种"正确"的方法来处理C++中的命名空间

Mr.*_*Boy 7 c++

我被Java,C#和AS3感染了,我一直想以同样的方式使用C++命名空间,但我一直在读,他们并没有真正考虑到这一点.

有没有正确的方法来使用命名空间?例如,在由十几个库项目组成的代码库中(比如图形,声音,数学等等)和几个应用程序项目,该怎么办?是对还是错/开发者偏好:

  • 将所有内容放在顶级MyCompanyNameMyProjectName命名空间中?
  • 为每个库创建一个(子)命名空间

是否有官方规则/指南作为C++的一部分,或者只有人们倾向于遵循的建议?

jal*_*alf 15

正如我在评论@Nim的答案中提到的那样,关键是要提出一个实用的结构.

例如,如果你看一下.NET框架,它的命名空间就有很长的名字并且是深层嵌套的(Say,System.Collections.Generic.List<T>).这同样适用于Java.对于嵌套的命名空间,你有很长的名字,没有任何效果.

我第一次创建一个List类时,我将遇到名称冲突,这是命名空间应该阻止的.(因为这似乎给了一个评论者一个错误的想法,当然我能够创建自己的List类.但是每次我使用它时,我都有可能遇到冲突."标准" List或它的命名空间都非常常用的,所以我很有可能using在命名空间上有一个,这意味着,如果我也想在同一个文件中引用我自己的 List类,我会发生冲突)

相比之下,C++标准库几乎将所有内容放在一个简单的std命名空间中(以及一些内容std::ios)

实际上,.NET命名空间实际上是浪费精力.它们没有效果.每个代码文件都以一长串列表开头using X; using Y; using Z,因此实际效果是在编写代码时没有任何名称空间实际生效.为了创建一个int列表,我就这样做了List<int>.命名空间基本消失了.

在C++中,人们不鼓励使用using namespace std,因此为了使用标准库符号,我们使用std前缀:std::vector<int>.

Boost使用类似的东西:几乎所有东西都在 boost根命名空间中.然后将一些复杂的库放在子命名空间中,例如boost::filesystem.或者boost::mpl,某些库具有通常命名的"仅供内部使用"命名空间aux,但它们旨在被用户隐藏(或至少被忽略).

这样可以更好地保留命名空间的优点:它们可以避免命名冲突.我可以(人们经常这样做,因为向量可以有几个不同的含义)定义我自己的vector类,它不会与之冲突 std::vector.

那么你的命名空间应该有多深层嵌套?我倾向于使用类似标准库的东西,加上一点.不要为所有内容创建新的命名空间,并保持命名空间名称简短.

也许你公司的所有代码都使用了一个共同的根命名空间Cpy.

在这种情况下,您可能会为每个产品设置一个命名空间Prod.过去那个?好吧,你可能有每个主要组件(Comp)的命名空间,基本上就是这样.

这里重要的是你几乎不必引用最外面的命名空间.您编写的代码将在内部Cpy::Prod,因此您需要输入的唯一名称空间前缀Comp::是简洁的,就像标准库一样std.我几乎从不必写Cpy::Prod::Comp,因为我的所有代码都已经在前两个命名空间内.如果不是这种情况,则命名空间结构太长且嵌套太深.

然后,我有时不喜欢加速,并创造小"内部"帮手命名空间,通常称为AuxUtil或相似.这些应该是小的,只能不断地从他们的直接父命名空间访问.特定组件可能有一些仅供内部使用的类.所以它们隐藏在一个小的Aux命名空间中,主要是为了让它们与引用我们组件的其他人隐藏起来.

当然,您可能会问自己,最外层的"公司"命名空间真正具有什么目的.是不是我们所有的代码都是,我们的公司?第三方代码通常(希望)在其自己的命名空间内(例如boost::),因此即使没有公司命名空间,我们也不应冒任何冲突的风险.您可能想要删除那个.

另一件需要考虑的事情是,如果您要编写库组件供外部使用,那么命名空间结构应该更短.在公司内部,您可以假设每个人都已在"公司"命名空间内编写代码,因此他们永远不必输入命名空间前缀.它基本上是"免费的".但是,如果外部用户必须引用您的代码,那么它们是一个额外的命名空间层,他们必须输入,这会很快变旧.整个"产品"命名空间可能是不可避免的(类似于stdboost),但您可能希望尽可能频繁地避免使用"产品"命名空间.(同样,像这两个一样,很少在根命名空间下创建子命名空间)

最重要的是,您的命名空间必须实用可用.如果强制用户在命名空间前缀中键入超过8个字符,那就会很烦人,而且它们只会开始放在using namespace X任何地方.您只需要命名空间,否则可能会发生名称冲突.您控制的代码永远不应该与第三方代码共享命名空间,因为您无法控制它们添加的名称(通常,第三方库通过将其库放在公共根名称空间中来处理此问题,例如boost).但是在你控制的代码中,不会有那么多碰撞.因此,不要定义比实际需要更多的命名空间.

  • @Steve:如果我在我的代码文件中引用"标准列表",我通常在其顶部放置一个`使用System.Collections.Generic',是吗?如果在同一个文件中,我需要引用List我在`Jalf.SomeOtherNamespace`中定义了自己,然后我还会在文件的顶部放置一个``Jalf.SomeOtherNamespace`.现在,如果在文件正文中输入`List <int>,我得到一个名称冲突.标识符`List <T>`是不明确的.所以是的,我在C#中得到了名称冲突,因为命名空间只要实际有用就会被选择性地禁用. (3认同)
  • +1为短名称和浅层次结构. (2认同)
  • @Steve:如果没有碰撞,怎么会有歧义?;)无论如何,就像你说的,最现实的选择开发商有一个是输入了*全*合格的名称,其中,在这些平台上,是*可笑长*..NET允许您为*个别*类定义别名,但不能为整个命名空间定义别名,这也可能使它成为一件苦差事.如果他们的命名空间结构不那么复杂,那么处理起来会更容易,这是我的观点.在C++中,这些变通方法的成本要低得多,我只需添加一个`std ::`前缀,而不是.NET中常见的英里长前缀. (2认同)

Nim*_*Nim 3

我认为这是非常主观的,你可能会收到很多不同的意见,所以这是我的!:)

嵌套命名空间——很好。一个大的命名空间——太可怕了

以上是考虑到现实世界(即非常大的代码库)。为了防止 RSI,请考虑短命名空间名称!;)

编辑:一个例子,它非常主观,其他人会有不同的方法......

假设您在 foo 公司工作,在 Java 中,通常以 com 开头,因此请使用 foo

namespace foo
{

}
Run Code Online (Sandbox Code Playgroud)

现在您公司的所有代码都位于一个命名空间中,接下来考虑任何共享的内容:

namespace foo
{
  namespace com
  {
    // any communication stuff goes here
    namespace msg
    {
      // let's say you have some form of messages that you send
    } // msg
    namespace con
    {
      // wraps all your connectivity
    } // con
  } // com

  namespace util
  {
    // utilities
    // you may not need to break this up further
  } // util
} // foo
Run Code Online (Sandbox Code Playgroud)

现在假设您有项目 bob,在项目中给它自己的命名空间

namespace foo
{
  namespace proj
  {
    // all projects are here
    namespace bob
    {
      // all bob's stuff is here, break it up as you need (though I wouldn't bother unless you have hundred's of classes where collisions are likely), I'd rather organise the files in the file system appropriately and keep the classes in the same namespace.
    } // bob

  } // proj
} // foo
Run Code Online (Sandbox Code Playgroud)

  • 由于您可以在使用名称空间时轻松地为名称空间创建短别名,因此为名称空间提供长名称是完全可以的(如果这有助于代码的清晰度)。 (3认同)