我在一个类中发现了这一行代码,我必须修改:
::Configuration * tmpCo = m_configurationDB;//pointer to current db
我不知道类名前的双冒号是什么意思。如果没有,我会读到:声明tmpCo作为类Configuration对象的指针…但是前面的双冒号把我弄糊涂了。
我还发现:
typedef ::config::set ConfigSet;
我在一个类中发现了这一行代码,我必须修改:
::Configuration * tmpCo = m_configurationDB;//pointer to current db
我不知道类名前的双冒号是什么意思。如果没有,我会读到:声明tmpCo作为类Configuration对象的指针…但是前面的双冒号把我弄糊涂了。
我还发现:
typedef ::config::set ConfigSet;
当前回答
已经有很多合理的答案了。我将插进一个比喻,可能会帮助一些读者。::工作起来很像文件系统目录分隔符'/',当你搜索你想要运行的程序时。考虑:
/path/to/executable
这是非常显式的——只有位于文件系统树中确切位置的可执行文件才能匹配此规范,而不考虑实际的PATH。同样……
::std::cout
...在c++命名空间“tree”中同样显式。
与这些绝对路径相比,你可以配置好的UNIX shell(例如zsh)来解析当前目录下的相对路径或PATH环境变量中的任何元素,因此如果PATH=/usr/bin:/usr/local/bin,并且你在/tmp中,那么…
X11/xterm
...如果找到/tmp/X11/xterm, else /usr/bin/X11/xterm, else /usr/local/bin/X11/xterm类似地,假设您在一个名为X的名称空间中,并且“正在使用名称空间Y”,那么……
std::cout
…可以在::X::std::cout,::std::cout,::Y::std::cout中的任何地方找到,并且可能由于依赖参数的查找(ADL,又名Koenig查找)而在其他地方找到。因此,only::std::cout真正明确了你指的是哪个对象,但幸运的是,没有哪个头脑正常的人会创建自己的类/结构或命名空间称为“std”,也不会创建任何名为“cout”的东西,所以在实践中只使用std::cout是可以的。
值得注意的差异:
1) shell倾向于使用PATH中的顺序来使用第一个匹配,而c++在你有歧义的时候会给出编译器错误。
2)在c++中,没有任何前导作用域的名称可以在当前命名空间中匹配,而大多数UNIX shell只在您放置。在PATH中。
3) c++总是搜索全局命名空间(就像/隐式地拥有你的PATH)。
关于命名空间和符号的显式性的一般性讨论
Using absolute ::abc::def::... "paths" can sometimes be useful to isolate you from any other namespaces you're using, part of but don't really have control over the content of, or even other libraries that your library's client code also uses. On the other hand, it also couples you more tightly to the existing "absolute" location of the symbol, and you miss the advantages of implicit matching in namespaces: less coupling, easier mobility of code between namespaces, and more concise, readable source code.
As with many things, it's a balancing act. The C++ Standard puts lots of identifiers under std:: that are less "unique" than cout, that programmers might use for something completely different in their code (e.g. merge, includes, fill, generate, exchange, queue, toupper, max). Two unrelated non-Standard libraries have a far higher chance of using the same identifiers as the authors are generally un- or less-aware of each other. And libraries - including the C++ Standard library - change their symbols over time. All this potentially creates ambiguity when recompiling old code, particularly when there's been heavy use of using namespaces: the worst thing you can do in this space is allow using namespaces in headers to escape the headers' scopes, such that an arbitrarily large amount of direct and indirect client code is unable to make their own decisions about which namespaces to use and how to manage ambiguities.
因此,前导::是c++程序员工具箱中的一个工具,用于主动消除已知冲突的歧义,和/或消除未来歧义的可能性....
其他回答
::是定义命名空间的运算符。
例如,如果您想使用cout而不提及使用名称空间std;在你的代码中,你这样写:
std::cout << "test";
当没有提到命名空间时,就说该类属于全局命名空间。
一个隐藏的全局名称可以使用作用域解析操作符引用:: 例如;
int x;
void f2()
{
int x = 1; // hide global x
::x = 2; // assign to global x
x = 2; // assign to local x
// ...
}
运算符被称为作用域解析运算符,它的作用就是解析作用域。因此,通过在type-name前面加上this,它告诉编译器在全局命名空间中查找类型。
例子:
int count = 0;
int main(void) {
int count = 0;
::count = 1; // set global count to 1
count = 2; // set local count to 2
return 0;
}
(这个答案主要是给谷歌人的,因为OP已经解决了他的问题。) 前置的::-作用域结果运算符-的含义已经在其他答案中描述过,但我想补充一下人们为什么使用它。
意思是“从全局命名空间取名称,而不是其他任何名称”。但是为什么需要明确地拼写呢?
用例-名称空间冲突
当全局命名空间和本地/嵌套命名空间中有相同的名称时,将使用本地名称空间。所以如果你想要全局的,在它前面加上::。这个案例在@Wyatt Anderson的回答中有描述,请看他的例子。
用例强调非成员函数
当你编写一个成员函数(一个方法)时,调用其他成员函数和调用非成员(free)函数看起来很像:
class A {
void DoSomething() {
m_counter=0;
...
Twist(data);
...
Bend(data);
...
if(m_counter>0) exit(0);
}
int m_couner;
...
}
但也有可能Twist是a类的姐妹成员函数,而Bend是一个自由函数。也就是说,Twist可以使用和修改m_counter,而Bend不能。因此,如果你想确保m_counter保持为0,你必须检查Twist,但你不需要检查Bend。
因此,为了使它更明显,可以这样写->Twist,向读者表明Twist是一个成员函数,或者写::Bend,表明Bend是自由函数。或两者兼而有之。这在您执行或计划重构时非常有用。
这确保解析是从全局名称空间进行的,而不是从您当前所在的名称空间开始。例如,如果你有两个不同的类叫做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)中的新定义所破坏。