有正确的使用命名空间的方法吗?例如,在由十几个库项目(比如图形、声音、数学等)和几个应用程序项目组成的代码库中,该怎么做?是否正确/错误/开发人员自定义:
- 将所有内容放在顶级
MyCompanyName
或 MyProjectName
命名空间下?
- 为每个库创建一个子命名空间?C++中是否有官方规则/指南,还是只有人们倾向于遵循的建议?
MyCompanyName
或 MyProjectName
命名空间下?
- 为每个库创建一个子命名空间?正如我在对@Nim的回答中提到的评论中所说,关键是要设计出一个实用的结构。
如果你看一下.NET框架,它的命名空间有着很长的名称并且嵌套非常深(例如,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::filesystem
或boost::mpl
,而一些库则有“仅内部使用”的命名空间,通常被命名为aux
,但它们旨在对用户不可见(至少被忽略)。vector
类,它不会与std::vector
冲突。Cpy
。Prod
。再往下呢?你可能会为每个主要组件(Comp
)创建一个命名空间,基本上就是这样了。Cpy::Prod
中,因此你需要输入的唯一命名空间前缀是Comp::
,它像标准库的std
一样简短而简洁。我几乎从不必写Cpy::Prod::Comp
,因为我的所有代码已经在前两个命名空间中了。如果情况不是这样,命名空间结构将会太长并且嵌套过深。有时候,我像 Boost 一样创建小的“内部”帮助命名空间,通常称为 Aux
或 Util
等。这些应该很小,并且只能从它们的直接父命名空间访问。一个特定的组件可能会有一些仅供内部使用的类。因此,它们被放在一个小的 Aux
命名空间中,主要是为了将它们隐藏起来,防止其他引用我们组件的人看到。
当然,您可能会问自己最外层的“公司”命名空间真正的目的是什么。难道不是我们所有的代码都属于公司吗?第三方代码通常(希望)会在其自己的命名空间内(例如,boost::
),因此即使没有公司命名空间,我们也不应该冒任何冲突的风险。您可能想删除它。
还有一件事需要考虑,如果您正在编写为外部使用的库组件,则命名空间结构应该更加简短。在公司内部,您可以假设每个人都已经在“公司”命名空间内编写代码,因此他们永远不必输入命名空间前缀。这基本上是“免费”的。但是,如果外部用户必须引用您的代码,则他们必须输入另一层命名空间,这很快就会变得烦人。一个总体的“产品”命名空间可能是不可避免的(类似于 std
或 boost
),但是您可能希望尽可能避免使用“产品”命名空间。(同样,像这两个示例,只在根命名空间下很少创建子命名空间)
关键是你的命名空间必须是实用和可用的。如果你强制用户在命名空间前缀中输入超过8个字符,这会很烦人,他们只会到处添加using namespace X
。你真正需要使用命名空间的情况是防止名称冲突。你控制的代码永远不应该与第三方代码共享命名空间,因为你无法控制他们添加的名称(通常,第三方库通过将其库放入公共根命名空间(如boost
)来解决此问题)。但是,在你控制的代码中,也不会有那么多碰撞。所以不要定义比你实际需要的更多的命名空间。
using System.Collections.Generic
并定义自己的List<T>
类,则不会出现任何名称冲突。甚至,如果您在同一范围内有一个名为List的命名空间和一个类List,也不会出现名称冲突。using
并没有“消除”命名空间。在头文件中,C++程序员只是被劝阻使用using namespace std
。在源文件中使用它很少有缺点;只有在您实际需要消除歧义时才应使用完整的命名空间名称(或别名)。 - Steve Musing System.Collections.Generic
,是吗?如果在同一文件中,我需要引用我自己在 Jalf.SomeOtherNamespace
中定义的 List,那么我还会在文件顶部加上 using Jalf.SomeOtherNamespace
。现在,在文件主体中,如果我键入 List<int>
,就会出现名称冲突。标识符 List<T>
是有歧义的。所以,是的,在C#中我会遇到名称冲突,因为命名空间在它们实际有用的任何时间都被选择性地禁用了。 - jalfstd::
前缀,而不是在.NET中常见的长长的前缀。 - jalfusing
也可以为命名空间设置别名。出于某种原因,我从来没有成功过,但我也从未查过,所以我认为这是不可能的。谢谢。 :) - jalfnamespace foo
{
}
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
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
namespace p_bob = foo::proj::bob;
然后 p_bob::myclass...
) - Nim