关于C ++中的全局命名空间

时间:2011-10-05 14:21:10

标签: c++ namespaces global

在C ++中,我们是否应该使用::

在全局命名空间中添加内容

例如,当使用C语言的WinAPI时,我应该::HANDLE而不是HANDLE,而::LoadLibrary而不是LoadLibrary吗? C ++对此有何看法?这通常是一个好主意,考虑可读性和可维护性等问题吗?

7 个答案:

答案 0 :(得分:8)

C ++中的名称可以是合格且不合格的。限定和非限定名称查找有不同的规则。 ::HANDLE是限定名,而HANDLE是不合格的名称。请考虑以下示例:

#include <windows.h>

int main()
{
    int HANDLE;
    HANDLE x; //ERROR HANDLE IS NOT A TYPE
    ::HANDLE y; //OK, qualified name lookup finds the global HANDLE
}

我认为选择HANDLE::HANDLE的决定是编码风格的问题。当然,正如我的例子所示,可能存在必须符合资格的情况。所以,你也可以使用::以防万一,除非语法对你有些恶心。

答案 1 :(得分:6)

由于C中不存在名称空间,请不要使用:: HANDLE来访问HANDLE类型。

使用prepending :: for全局命名空间对于可读性是一个好主意,您知道要访问的类型来自全局命名空间。

此外,如果你在一个嵌套的命名空间中并声明自己的HANDLE类型(例如),那么编译器将使用这个而不是windows.h!

因此,在嵌套命名空间中工作时,总是更喜欢使用::之前的名称。

答案 2 :(得分:5)

主要的兴趣点是从编译器的角度来看差异是什么,正如已经说过的那样,如果你包含::,那么你使用的是合格的查找,而不是不合格的查找。

使用限定查找的优点是它能够始终精确定位特定符号。缺点是它总能精确定位该特定符号 - 即。它将禁用Argument Dependent Lookup。 ADL是该语言的一个重要且有用的部分,通过限定你有效地禁用它,这很糟糕。

考虑到全局命名空间中有一个函数f,并且在命名空间T中添加了一个类型N。不要认为您想要添加f的重载,以T作为参数。遵循接口原则,您可以将f添加到N命名空间,因为f实际上是对T执行的操作,因此属于该类型。在这种情况下,如果您的代码在未知类型::f(obj)的对象上调用(考虑通用代码)U,则编译器将无法选择::N::f(obj)作为潜在重载代码明确要求全局命名空间中的重载。

使用非限定查找使您可以自由地定义它们所属的函数以及用作参数的类型。虽然它不完全相同,但考虑使用swap,如果您符合std::swap的条件,那么它就不会在void swap( T&, T& )命名空间中提取您的N

当编译器无法获取我想要的元素时,我只会完全限定标识符。

答案 3 :(得分:4)

这主要是风格问题;没有性能或效率问题可言。对于打算在许多不同平台上编译的大型项目和项目来说,这是一种很好的做法,因为在这种情况下,全局名称和命名空间中的名称之间的冲突更有可能发生。

答案 4 :(得分:4)

通常,必须为全局命名空间添加::。 (仅在一些非常罕见的情况下)。恕我直言,它会损害可读性,但另一方面它可能不会破坏你的代码

答案 5 :(得分:2)

我将所有代码放入命名空间,而且我更喜欢C头上的C ++标头,因此全局命名空间中剩下的唯一符号往往来自Windows API。我避免将符号从其他名称空间拉到当前名称空间中(例如,我从来没有using namespace std;),而是选择明确地限定事物。这符合Google's C++ style guide

我因此养成了使用::验证WinAPI函数调用的习惯,原因如下:

  1. 一致性。对于当前命名空间之外的所有内容,我明确地引用它(例如,std::string),那么为什么不明确地引用Windows API(例如::LoadLibraryW)? Windows API命名空间全局命名空间。

  2. 许多WinAPI函数通常被命名(例如,DeleteObject)。除非您非常熟悉正在阅读的代码,否则您可能不知道DeleteObject是对当前命名空间中的某些内容还是对Windows API的调用。因此,我发现::澄清了。

  3. 许多Windows框架都有与原始调用同名的方法。例如,ATL::CWindow具有GetClientRect方法,其签名与WinAPI的GetClientRect略有不同。在此框架中,您的类通常派生自ATL::CWindow,因此,在您的类的实现中,如果需要,调用继承的ATL方法GetClientRect::GetClientRect是正常的。调用WinAPI函数。这不是绝对必要的,因为编译器将根据签名找到正确的。然而,我发现这种区别为读者澄清了。

  4. (我知道这个问题并不是关于WinAPI的,但是这个例子是关于WinAPI的。)

答案 6 :(得分:1)

不,如果您的班级中没有LoadLibrary方法,则 不需要来使用全局范围。事实上,你不应该使用全局范围,因为如果你以后在你的课程中添加LoadLibrary,你的意图可能是覆盖全局函数......