::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;
这将确保从全局命名空间开始解析,而不是从当前所在的命名空间开始。例如,如果您有两个不同的类都叫做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(...)
中为什么要放置两组双冒号? - Azurespot::
是指命名空间或类及其成员。但第一个是什么意思? - Azurespot::
运算符被称为作用域解析运算符,它的作用就是解析作用域。因此,通过在类型名称前面加上它,告诉编译器在全局命名空间中查找该类型。
示例:
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;
}
::
的工作方式很像文件系统目录分隔符'/
'。考虑以下内容:/path/to/executable
这非常明确——只有文件系统树中该精确位置的可执行文件才能匹配此规范,与当前生效的PATH无关。同样地...
::std::cout
...在C++命名空间"tree"中同样明确。
与这种绝对路径相反,你可以配置好的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 tend to use the first match using the ordering in PATH
,而C ++在模糊时会给出编译器错误。
2)在C ++中,没有任何前导作用域的名称可以与当前命名空间匹配,而大多数UNIX shell只有在PATH
中放置.
时才这样做。
3)C ++始终搜索全局命名空间(就像在您的PATH
中隐式地拥有/
一样)。
使用绝对路径::abc::def::...
有时可以将您与正在使用的任何其他命名空间隔离开来,这些命名空间是您部分拥有但无法真正控制其内容的一部分,甚至包括您的库的客户端代码也使用的其他库。另一方面,它也将您更紧密地耦合到符号的现有“绝对”位置,并且会错过命名空间中隐式匹配的优点:减少耦合,更容易在命名空间之间移动代码,以及更简洁,可读性更强的源代码。
像许多事情一样,这是一个平衡的行为。 C ++标准将许多标识符放在std ::
下,这些标识符比cout
不太“独特”,程序员可能会在其代码中完全使用它们进行不同的操作(例如merge
,includes
,fill
,generate
,exchange
,queue
,toupper
,max
)。 两个不相关的非标准库具有更高的使用相同标识符的机会,因为作者通常不知道或不太了解彼此。而且库 - 包括C ++标准库 - 随时间而改变其符号。所有这些都可能在重新编译旧代码时创建歧义,特别是当有大量使用using namespace
时:在此空间中最糟糕的事情是允许头文件中的using namespace
逃脱头文件范围,以便任意数量的直接和间接客户端代码无法自行决定要使用哪个命名空间以及如何管理模糊性。
因此,C++程序员的工具箱中一个领先的::
是积极消除已知冲突和/或消除未来不确定性的一种工具。
example.org.
明确地根植于全球命名空间,不像example.org
那样模糊不清。但我猜有些读者对此可能不太熟悉。 - Toby Speightexample.org.
明确地根植于全球命名空间,不像example.org
那样含糊不清。但我猜有些读者对此不太熟悉。 - undefined::
是作用域解析运算符,用于指定某个东西的作用域。
例如,::
单独表示全局作用域,不在任何其他命名空间内。
some::thing
可以有以下的几种可能意义:
some
是一个命名空间(在全局作用域或当前作用域之外)而thing
则可以是类型、函数、对象或嵌套命名空间;some
是当前作用域中可用的类,而thing
则可以是这个类的成员对象、函数或类型;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_ext
的成员函数中写入some::thing
时,它指的是基类型some
中的thing
对象。如果没有使用some::
,那么thing
就表示最近的作用域中的some_ext::thing
。这样更清晰明了吗? - Klaim::
用于将某个东西(变量、函数、类、typedef等)链接到命名空间或类中。
如果在 ::
前面没有左手边,则说明您正在使用全局命名空间。
例如:
::doMyGlobalFunction();
它被称为作用域解析运算符,可以使用作用域解析运算符::引用隐藏的全局名称。
例如;
int x;
void f2()
{
int x = 1; // hide global x
::x = 2; // assign to global x
x = 2; // assign to local x
// ...
}
(这个回答主要是为了方便谷歌搜索,因为问题提出者已经解决了他的问题。)在其他答案中已经解释了带有::
的前缀的含义——作用域分辨符,但我想补充一下人们为什么会使用它。
它的含义是“从全局命名空间中获取名称,而不是其他任何地方”。但是为什么需要明确地拼写呢?
用例 - 命名空间冲突
当您在全局命名空间和本地/嵌套命名空间中具有相同的名称时,将使用本地的那一个。因此,如果您想要全局的那一个,请在名称前面加上::
。这种情况已在@Wyatt Anderson的答案中描述,请参见他的示例。
用例 - 强调非成员函数
当你编写成员函数(方法)时,调用其他成员函数和调用非成员(自由)函数看起来很像:
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_couner
,而Bend
则不能。因此,如果你想确保m_counter
保持为0,你需要检查Twist
,但不需要检查Bend
。
因此,为了使这更加清晰明了,可以使用this->Twist
来显示Twist
是一个成员函数,或者使用::Bend
来显示Bend
是自由函数。或者两者兼备。当你进行或计划重构时,这非常有用。
::
是定义命名空间的运算符。
例如,如果您想在代码中使用cout而不提及using namespace std;
,则可以这样写:
std::cout << "test";
当没有提及命名空间时,就意味着该类属于全局命名空间。
“::”代表作用域解析运算符。如果两个不同的类中有相同名称的函数/方法,可以使用作用域解析运算符来访问特定类的方法。
"
::
表示从全局/匿名命名空间引用变量。 - wkl