C ++命名空间,与Java包的比较

我最近完成了一堆Java编码,并且已经习惯了非常特定的软件包命名系统,例如深度嵌套。 com.company.project.db。在Java,AS3 / Flex和C#中运行正常。 我也曾经在C ++中看到过相同的范例,但是我也听说将C ++名称空间视为Java包的直接对应对象是很不好的。

是真的,为什么? 名称空间/程序包有何相似之处和不同之处? 如果您使用深层嵌套的名称空间,可能会出现什么问题?

Mr. Boy asked 2020-08-12T03:55:03Z
7个解决方案
28 votes

在C ++中,名称空间只是关于对可用名称进行分区。 Java软件包与模块有关。 命名层次结构只是它的一方面。

就本质而言,在C ++中使用深度嵌套的名称空间并没有什么错,除了它们通常不需要,因为它们背后没有模块系统,而额外的层只会增加噪音。通常只有一个或两个级别的名称空间就足够了,而对于内部详细信息(通常简称为“详细信息”)来说,这是一个奇怪的额外级别。

C ++命名空间还存在一些额外的规则,如果这些规则被过度使用,它们可能会吸引您-例如,参数依赖查找以及解析为父级的规则。 WRT后者,取:

namespace a{ namespace b{ int x; } }
namespace b{ string x; }
namespace a
{
  b::x = 42;
}

这合法吗? 很明显发生了什么事吗?您需要知道名称空间解析的优先级才能回答这些问题。

philsquared answered 2020-08-12T03:55:22Z
19 votes

Java软件包不是嵌套的,而是扁平的。 任何明显的嵌套都不过是命名约定。

例如,程序包com.company.project.dbcom.company.projectcom.company.project.db.x没有任何关系。com.company.project.db中的代码对com.company.project.db.x中的代码的访问比对300759847256142142746中的代码没有更多的访问。

skaffman answered 2020-08-12T03:55:48Z
5 votes

以下是C ++名称空间与Java或C#名称空间不同的原因。

避免冲突

在Java / C#语言中,名称空间旨在避免类库不同部分中的名称之间发生冲突。 您可能在C#的名称空间层次结构中的5个不同位置拥有名为“ Watcher”的类。 在C ++中,如果库中存在相同的命名类,则将其放置在另一个类中而不是创建名称空间。 这样的嵌套类都很好并且受到鼓励,实际上,语法也将类视为使用::运算符的名称空间。

嵌套的命名空间应该是多少?

流行的库如Boost,Eigen以及STL当然提供了很好的例子。 这些库通常将几乎所有内容都填充到一个名称空间中,如A::B::C::Dusing namespaceusing namespace。很少有组件具有其自己的名称空间,例如typedefs563或using name =。关于何时使用第二级没有统一的规则,但看起来似乎很大或单独开发/维护 或可选组件通常具有自己的名称空间。 第三级甚至更罕见。 通常,我使用结构company::project并用于项目company::project::component的大型独立可用子系统。

避免外部库中的冲突

现在有个大问题:如果您从两个不同的人那里获得两个具有完全相同的名称空间和类的库,该怎么办? 这种情况相当罕见,因为大多数人倾向于至少以他们的项目名称包装他们的库。 即使项目名称相同,您最终都使用这两个库的情况更为罕见。 但是,有时对项目名称(ahm ...“地铁”,“ apollo” ...)做出错误的决定,甚至根本不使用名称空间。 如果发生这种情况,您可以将其中一个或两个库的#include包装到名称空间中,即可解决冲突! 这是人们不为冲突而烦恼的一个原因,因为解决冲突是微不足道的。 如果遵循使用A::B::C::D的做法,那么冲突将变得极为罕见。

语言差异

尽管C ++像C#一样提供A::B::C::D语句,但通常将其“导入”您自己的命名空间中的所有内容视为一种不好的做法。 这样做的原因是,标题可能包含许多“不良”内容,包括重新定义使您完全感到意外的内容。 这与C#/ Java完全不同,在C#/ Java中,当您执行等效的using namespace时,您只会获得干净的公共接口。(注意:在C ++中,您可以通过使用Pimpl模式来实现相同的操作,但是通常这样做会产生过多的额外负担,而实际上很少有库会这样做 它)。 因此,您几乎从不希望执行using namespace。相反,您实际上要使用typedefs(或using name =)。 这再次使深度嵌套的名称空间无法使用。

组织代码

在Java / C#中,人们倾向于在文件夹中组织很多代码。通常,随着文件夹增长超过20个甚至10个文件,人们会开始考虑文件夹。在C ++中,情况更加多样化,但是对于许多大型项目而言,更平坦的目录结构是首选。例如,标准库的std文件夹有53个文件,而Facebook的愚蠢项目似乎走了同样的路。我认为,造成这种情况的一个原因可能是Java / C#人们更多地使用可视化IDE,并且在文件夹导航中使用鼠标滚动,而不是控制台,在控制台中,您可以使用通配符查找平面结构的文件。同样,C ++程序员绝对不要回避在单个文件中放置多个类,并将文件命名为逻辑单元,而不是与C#或Java中的类名相同。这样可以加快编译速度,这对于大型项目非常重要。尽管没有语言级别的要求,每个文件夹都拥有自己的名称空间,但许多C ++开发人员更喜欢为每个文件夹分配其自己的名称空间,并保持文件夹层次结构为2级或更少。

可能的例外

在C ++中,如果您已经在A::B中,则可以仅将A::B::C::D称为C::D。因此,如果您想要进一步下推私有代码或较少使用的类,则可以这样做,同时仍将自己的相对深度保持在2左右。 。 在这种情况下,您可能还想为每个级别创建文件夹,以便文件位置是可预测的。 通常,该领域没有黄金标准,但是您不希望过度模仿C#/ Java的深度嵌套名称空间。

有关

  • 避免头文件中的冲突; 使用名称空间包装器?

  • 是否有“正确”的方式在C ++中处理名称空间

  • 在C ++中使用标准名称

  • Java软件包与C ++库

  • 有没有更好的方法可以在标头中用C ++表示嵌套的名称空间

  • 您如何在C ++中正确使用名称空间?

Shital Shah answered 2020-08-12T03:57:38Z
0 votes

您可以在C ++中具有嵌套的名称空间。

但是,它们显然与Java中的工作方式不同。 Java软件包的定义确实要好得多,并且没有真正的静态初始化异常。 使用C ++,名称空间很有帮助,但仍然存在相当大的危险。

Charles Eli Cheese answered 2020-08-12T03:58:03Z
0 votes

在C ++中,设计和实现的基本单位是类,而不是名称空间。 命名空间旨在防止大型库中的名称冲突,而不是用于表达概念。

与命名空间相比,类具有几个优点:

  • 他们可以有构造函数和析构函数
  • 他们可以有私人成员
  • 他们不能重新打开

但是,我会仔细研究任何深层嵌套的关系。 这确实不是设计软件的好方法,并且会导致无法读取的代码,无论您使用类还是名称空间。

answered 2020-08-12T03:58:46Z
0 votes

我认为以前的答案中缺少某些内容,这是我非常喜欢C ++的原因之一。

想象一下,您正在对图形应用程序进行编程,突然间您意识到所有小部件中都有一些共同点。 您希望它们都具有新功能。 你是做什么?

1)编辑基本窗口小部件类? 可以,但是很可能您无权访问它。 也许存在许可问题,使您无法进行自己的修改。 即使您可以做到,即使它只对您的项目有意义,作者也不会在将来的版本中包括它,并且升级工具包将更加痛苦。

2)创建一个接口类/多继承? 根据您现有的代码,更新与小部件相关的每个单个类或多或少会很麻烦。 这样做,代码的维护成本将更高,因为定义新类的每个人都必须知道他们应该继承自您的接口。 依赖他人纪律确实是冒险的。

这里的C ++名称空间的妙处在于,您可以使用另一种方式将内容封装在现有系统中。 您不仅可以封装在无法编辑的现有库中,还可以封装无法轻松插入类/对象层次结构的类似概念。

Java迫使您将更多的精力放在纯OOP设计上。 当然,我告诉您的是您可能是个肮脏的黑客,但并不优雅,但是有很多懒惰的人在编程,他们不花时间来修复他们的设计。

SystematicFrank answered 2020-08-12T03:59:32Z
0 votes

我将介绍一些我听过但不了解其真实性的内容,请帮助确认/消除它们。

  1. C ++性能(以某种方式)受较长的完整指定的方法名称的影响,例如namespace1::namespace2::namespace3::classX::method123()

  2. 您可能会在编译器/链接器中达到允许的符号长度限制

Mr. Boy answered 2020-08-12T04:00:02Z
translate from https://stackoverflow.com:/questions/2108172/c-namespaces-comparison-to-java-packages