为什么要使用命名空间?

3

这让我很困惑。所有的代码示例都涉及到namespaceAnamespaceB以及方法名称foo()bar(),这并没有帮助,反而更加混乱。每个人解释命名空间的方式好像都在暗示,命名空间是面向对象编程(OOP)时代的遗物,当你无法说“类汽车提供燃油水平”的时候,只能换一种方式来访问。但现在我想要进行 C++ 编程,使用命名空间有何意义?不光是头文件已经够令人困惑的了,命名空间根本没有任何意义,无论是在它们如何工作还是为什么要使用它们方面。

假设我有一个围绕着Traffic的项目。例如,你可以为 Car 及其组件、Driver 和 Passenger 以及道路 Road 建立类。 现在,该 Road 有 Car,每个 Car 都有 Person 。这会是什么样子?

你会创建 Road, Car, Person 命名空间吗?main() 将使用命名空间 Road 来访问头文件中的内容吗?在命名空间 Road 中包括命名空间 Car, 命名空间 Car 包括命名空间 Person,通过这种方式,main() 可以访问 Person 中的方法吗?虽然大多数指南都是这样解释的,但我并不真正明白它与仅导入头文件相比的优点,这是否产生相同的效果?

或者你会把多个头文件放在同一个命名空间下,例如 namespace Traffic 拥有所有这些类?可以嵌套命名空间吗?

我了解 C#,直到现在查找信息时才知道它有命名空间,而且从未需要过它,在 Java、Python 和 Dart 中也没有用到。由于我试图自学 C++,所以现在陷入困境,在这里提出这个问题。到目前为止,我也从未在 C++ 中使用过它们,但我想以正确的方式学习。


1
Python模块创建隐式命名空间。我不知道Java和Dart是否也有这个功能。 - R Sahu
1
Java有包,它们将名称分区。 - StoryTeller - Unslander Monica
相关/可能重复:https://dev59.com/tG855IYBdhLWcg3wq2TL请使用命名空间的原因和方法。 - NathanOliver
1
同时,参见:https://dev59.com/anVD5IYBdhLWcg3wQJKT - NathanOliver
1
在你的Road/Car/Person示例中,我希望这些类可能位于名为Models或类似名称的命名空间中。我无法想象为什么您要为每个类创建一个命名空间,因为其目的是将类逻辑地分组在一起。 - David
1
在C++添加命名空间之前,有些人会使用结构体作为临时命名空间以帮助收集和组织组件。但是这种方法存在某些不良行为,而命名空间则没有这些问题。因此,在C++发展的过程中,正式向语言中添加了“命名空间”关键字,并将标准C++库放置于::std命名空间中。 - Eljay
4个回答

7
对于小型、自包含的项目,不需要使用命名空间,在代码中不必为每个对象或概念创建一个命名空间。
使用库的大型项目受益于与这些库引入的名称隔离,以及一些内部组织使可读性更强。
同样,在创建库时,将其内容放入命名空间是一个好方法,以避免为用户带来麻烦和冲突(因为您不知道他们的项目有多大,以及他们可能想使用什么名称)。
打个比方:如果你有三本书,你不会费心将它们按字母顺序组织起来。但是,一旦你有了一百本,你可能会决定将它们分类存放在书架上,以便更容易参考和维护心理健康。
而且,如果现在从朋友那里借了另外二十本书,你可能会将它们放在一个单独的堆中,以便在需要归还时更容易找到它们。
所以,在某种程度上,这是一个情况...当你需要时,你就知道你需要它。

2
如果我创建了一个带有函数calculateStuff()的库,而你也创建了一个带有calculateStuff()函数的库,那么想要同时使用我们两个库的其他人将会很困扰。但是,如果我们都使用命名空间,就没有问题了,因为他/她可以将函数区分为myNamespace::calculateStuff()yourNamespace::calculateStuff(),就不会出现歧义。
例如:std::shared_ptrboost::shared_ptr。如果没有命名空间,您将无法在同一程序中同时使用它们,因为名称shared_ptr会产生歧义。

1
另一个常见例子是标准C++库中的std::bind()和Winsock库中的::bind()。如果没有命名空间,应该调用哪个bind()?编译器很难弄清楚这一点。使用适当的命名空间限定符来调用bind()即可解决问题。 - Remy Lebeau

1
"[Named] Namespaces"是一种将标识符空间进行细分的方法,正如名称所示。除了解决字面上的冲突(“你有多个foo...”),它还使得在由数百甚至数千个模块组成的大型、成熟的程序中查找foo变得更加容易。
变量或例程的“名称”可能会暗示它是什么,但可能不会给出任何关于位置或它所涉及的上下文(不是技术术语)的提示:“它只是成千上万个名称中的一个。” 但是,如果现在将它们分组到智能选择的命名空间中,则为它们添加了一层有用的组织水平。在典型的“庞大的程序”中,特别是那些(通常也是如此...)“并非完全熟悉”的程序中,这额外的面包屑级别是一个巨大的奖励。

1

简单地说,命名空间允许在不同的上下文中使用相同的名称。

假设你想创建两个函数,它们接受相同的参数并以两种不同的方式输出文本,为了简单起见,你想将它们都称为print()

由于它们都接受相同的参数,在这里不存在函数重载的机会,但是如果将每个函数放在单独的命名空间中,然后调用print(),你可以通过每次调用不同的命名空间来简单地更改函数的功能。


在这个例子中,最好使用不同的、自我说明的函数名称。 - Asteroids With Wings
如果你在处理更大规模的项目时,想要轻松地在两个大型函数集之间切换,这种方法可能会很有用。虽然这只是一个非常具体的例子,但它演示了使用命名空间的一种方式,可以让你受益匪浅。 - The Riser

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接