Answers:
这样可以确保解析是从全局名称空间进行的,而不是从当前所在的名称空间开始。例如,如果您有两个这样的不同类Configuration
:
class Configuration; // class 1, in global namespace
namespace MyApp
{
class Configuration; // class 2, different from class 1
function blah()
{
// resolves to MyApp::Configuration, class 2
Configuration::doStuff(...)
// resolves to top-level Configuration, class 1
::Configuration::doStuff(...)
}
}
基本上,它允许您遍历全局名称空间,因为在这种情况下,您的名称可能会被另一个名称空间内的新定义所破坏MyApp
。
::Configuration::doStuff(...)
::
两个术语之间是指名称空间或类及其成员。但是第一个呢?
已经有很多合理的答案。我会打个比方,以帮助一些读者。 在路径中搜索要运行的程序时,::
其工作原理与文件系统目录分隔符“ /
”非常相似。考虑:
/path/to/executable
这非常明确-不管有效的PATH如何,只有文件系统树中该确切位置的可执行文件都可以匹配此规范。同样...
::std::cout
...在C ++名称空间“树”中同样明确。
与此类绝对路径相反,您可以配置良好的UNIX Shell(例如zsh)来解析当前目录下或环境变量中任何元素下的相对路径PATH
,因此,如果PATH=/usr/bin:/usr/local/bin
,并且您在“中” /tmp
,则...
X11/xterm
...会愉快地运行/tmp/X11/xterm
,如果发现了,否则/usr/bin/X11/xterm
,其他/usr/local/bin/X11/xterm
。同样,假设您在一个名为的命名空间中X
,并且实际上有一个“ using namespace Y
”,然后...
std::cout
...可以在任何的发现::X::std::cout
,::std::cout
,::Y::std::cout
,和其他可能的地方由于参数相关查找(ADL,又称Koenig查找)。因此,只有::std::cout
真正明确地表明您所指的对象是什么,但是幸运的是,任何人都不会在自己的头脑中创建自己的名为“ std
” 的类/结构或命名空间,也不会创建任何名为“ cout
”的东西,因此在实践中只使用它std::cout
是可以的。
值得注意的差异:
1)shell倾向于使用中的顺序使用第一个匹配项PATH
,而当您不清楚时,C ++会给出编译器错误。
2)在C ++中,可以在当前名称空间中匹配没有任何前导作用域的名称,而大多数UNIX shell仅.
在将PATH
。放在其中时才能进行匹配。
3)C ++始终搜索全局名称空间(例如/
隐式地包含your PATH
)。
使用绝对的::abc::def::...
“路径”有时可能有助于将您与正在使用的任何其他命名空间隔离开来,这些命名空间是其中一部分,但实际上无法控制您的库的客户端代码也使用的其他库的内容,甚至无法对其进行控制。另一方面,它还将您更紧密地耦合到符号的现有“绝对”位置,并且您错过了名称空间中隐式匹配的优点:更少的耦合,更容易在名称空间之间移动代码以及更简洁,可读的源代码。
与许多事情一样,这是一种平衡行为。C ++标准放大量下标识符std::
是小于“独一无二”的cout
,程序员可以使用在他们的代码完全不同的东西(例如merge
,includes
,fill
,generate
,exchange
,queue
,toupper
,max
)。两个不相关的非标准库使用相同标识符的可能性要高得多,因为作者通常彼此之间不太了解。库-包括C ++标准库-会随着时间的推移更改其符号。当重新编译旧代码时,所有这些可能会造成歧义,尤其是在大量使用using namespace
s:在此空间中最糟糕的事情是允许using namespace
标头中的s可以逃避标头的范围,以至于任意数量的直接和间接客户端代码无法自行决定使用哪个名称空间以及如何管理歧义。
因此,领导::
是C ++程序员工具箱中的一种工具,用于主动消除已知冲突,和/或消除将来出现歧义的可能性...。
::
是范围解析运算符。它用于指定事物的范围。
例如,::
在所有其他名称空间之外,仅是全局范围。
some::thing
可以通过以下任何一种方式进行解释:
some
是一个名称空间(在全局范围内,或在当前范围之外的外部范围内),并且thing
是类型,函数,对象或嵌套名称空间;some
是一个类在当前范围内可用的并且thing
是一个成员对象,功能或类型的的some
类;some
可以是当前类型的基本类型(或当前类型本身),thing
然后是该类的一个成员,类型,函数或对象。您还可以嵌套嵌套范围,如中所示some::thing::bad
。在这里,每个名称可以是类型,对象或名称空间。此外,最后一个bad
也可以是一个函数。其他函数则不能,因为函数无法在其内部范围内公开任何内容。
因此,回到您的示例,::thing
它只能是全局范围内的某种东西:类型,函数,对象或名称空间。
您使用它的方式表明(用在指针声明中)它是全局范围中的一种类型。
我希望这个答案是完整且正确的,以帮助您了解范围解析。
class some { protected: int thing; }; class some_ext : public some { float thing; void action(){ some::thing = 42; thing = 666; } };
这some
是的基类,some_ext
当您写入some::thing
some_ext的成员函数时,意味着该thing
对象成为基类some
。没有some::
,thing
单独表示thing
最接近的范围,即some_ext::thing
。更清楚了吗?
::
用于将某些内容(变量,函数,类,typedef等)链接到名称空间或类。
如果之前没有左手边::
,则表明您正在使用全局名称空间。
例如:
::doMyGlobalFunction();
它的调用范围解析运算符,可以使用范围解析运算符::来引用一个隐藏的全局名称
:
int x;
void f2()
{
int x = 1; // hide global x
::x = 2; // assign to global x
x = 2; // assign to local x
// ...
}
(此答案主要是针对Google员工的,因为OP已经解决了他的问题。)::
在其他答案中已经说明了前置的含义-范围重新确定运算符-,但我想补充一下人们为什么使用它。
含义是“从全局名称空间获取名称,而不是其他任何名称”。但是,为什么需要对此进行明确的拼写?
用例-名称空间冲突
当您在全局名称空间和本地/嵌套名称空间中具有相同的名称时,将使用本地名称。因此,如果您想要全局的,请在前面加上::
。@Wyatt Anderson的回答描述了这个案例,请看他的例子。
用例-强调非成员功能
在编写成员函数(方法)时,对其他成员函数的调用和对非成员(自由)函数的调用看起来相似:
class A {
void DoSomething() {
m_counter=0;
...
Twist(data);
...
Bend(data);
...
if(m_counter>0) exit(0);
}
int m_couner;
...
}
但是可能Twist
是class的姐妹成员函数A
,并且Bend
是自由函数。也就是说,Twist
可以使用和修改m_couner
而Bend
不能。因此,如果要确保m_counter
保持为0,则必须检查Twist
,但是不需要进行检查Bend
。
因此,为了使这更清楚地突出,一个可以写this->Twist
向读者展示这Twist
是一个成员函数或写::Bend
证明Bend
是免费的。或两者。在进行或计划重构时,这非常有用。
::
是定义名称空间的运算符。
例如,如果要使用cout而不using namespace std;
在代码中提及,请编写以下代码:
std::cout << "test";
当没有提到命名空间时,可以说该类属于全局命名空间。
::
手段指的是来自全局/匿名命名空间的变量。