prepended double colon“::”是什么意思?

时间:2010-11-24 16:24:25

标签: c++ syntax namespaces scope-resolution global-namespace

我在类中找到了这行代码,我必须修改:

::Configuration * tmpCo = m_configurationDB;//pointer to current db

我不知道在类名前加上双冒号的确切含义。如果没有这个,我会读到:声明tmpCo作为指向类Configuration的对象的指针......但是前面的双冒号让我感到困惑。

我还发现:

typedef ::config::set ConfigSet;

9 个答案:

答案 0 :(得分:425)

这确保从全局命名空间发生解析,而不是从您当前所在的命名空间开始。例如,如果您有两个不同的类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

答案 1 :(得分:174)

::运算符称为范围解析运算符,只是这样,它解析了范围。因此,通过在其前面添加类型名称,它会告诉编译器在类型的全局命名空间中查找。

示例:

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;
}

答案 2 :(得分:104)

已经有很多合理的答案。我将通过一个可能有助于一些读者的类比来填写。在搜索您要运行的程序的路径时,::与文件系统目录分隔符“/”非常相似。考虑:

/path/to/executable

这非常明确 - 只有文件系统树中该位置的可执行文件才能匹配此规范,无论PATH生效。同样...

::std::cout

...在C ++命名空间“tree”中同样明确。

与此类绝对路径相比,您可以配置好的UNIX shell(例如zsh)来解析当前目录下的相对路径或PATH环境变量中的任何元素,如果是PATH=/usr/bin:/usr/local/bin,而你是“{”1 {},那么......

/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以及argument-dependent lookup(ADL,又名Koenig查找)中的任何其他地方找到。因此,只有::Y::std::cout确切地说明了你的意思究竟是哪个对象,但幸运的是,正确思想中的任何人都不会创建自己的类/结构或称为“::std::cout”的命名空间,也不会创建任何名为“{{{ 1}}“,所以实际上只使用std就好了。

值得注意的差异

1)shell倾向于使用cout中的排序使用第一个匹配,而C ++在你不明确时会给出编译器错误。

2)在C ++中,当前命名空间中可以匹配没有任何前导作用域的名称,而大多数UNIX shell只有在std::cout中放置PATH时才会这样做。

3)C ++总是搜索全局命名空间(比如.隐含地PATH)。

关于名称空间和符号显式性的一般性讨论

使用绝对/“路径”有时可以帮助您将您与正在使用的任何其他命名空间隔离开来,但实际上并不能控制您的库的内容,甚至是其他库客户端代码也使用。另一方面,它还将您更紧密地耦合到符号的现有“绝对”位置,并且您错过了名称空间中隐式匹配的优点:更少的耦合,更容易在命名空间之间移动代码,以及更简洁,可读的源代码

与许多事情一样,这是一种平衡行为。 C ++标准在PATH下放置了许多不比::abc::def::...“独特”的标识符,程序员可能会在代码中使用完全不同的内容(例如std::coutmergeincludesfillgenerateexchangequeue)。两个不相关的非标准库具有使用相同标识符的机会要高得多,因为作者通常彼此不了解或不太了解。而库 - 包括C ++标准库 - 随着时间的推移会改变它们的符号。所有这些都可能在重新编译旧代码时产生歧义,特别是在大量使用toupper时:在这个空间中你可以做的最糟糕的事情是允许标题中的max转义标题的范围,因此,任意大量的直接和间接客户端代码无法自行决定使用哪些命名空间以及如何管理歧义。

因此,领先的using namespace是C ++程序员工具箱中的一个工具,可以主动消除已知冲突的歧义,和/或消除未来模糊的可能性....

答案 3 :(得分:34)

::是范围解析运算符。它用于指定某事物的范围。

例如,::单独是全局范围,在所有其他名称空间之外。

some::thing可以通过以下任何方式解释:

  • some命名空间(在全局范围内,或者是当前范围外的范围),thing类型功能对象嵌套命名空间;
  • some是当前范围内的thing成员对象功能some类的类型;
  • 在班级成员函数中some可以是当前类型的基本类型(或当前类型本身)和thing然后是此类的一员,类型功能对象

您也可以拥有嵌套范围,如some::thing::bad中所示。这里每个名称可以是类型,对象或命名空间。另外,最后一个bad也可以是一个函数。其他人不能,因为函数不能在其内部范围内暴露任何东西。

因此,回到您的示例,::thing只能是全局范围内的东西:类型,函数,对象或命名空间。

您使用它的方式建议(在指针声明中使用)它是全局范围中的类型。

我希望这个答案是完整和正确的,足以帮助您了解范围解析。

答案 4 :(得分:14)

::用于将某些东西(变量,函数,类,类型等等...)链接到命名空间或类。

如果::之前没有左侧,那么它会强调您使用全局命名空间的事实。

e.g:

::doMyGlobalFunction();

答案 5 :(得分:9)

其调用范围解析运算符,可以使用范围解析运算符引用隐藏的全局名称::
例如;

int x;
void f2()
{
   int x = 1; // hide global x
   ::x = 2; // assign to global x
   x = 2; // assign to local x
   // ...
}

答案 6 :(得分:5)

(这个答案主要针对的是googlers,因为OP已经解决了他的问题。) 前置:: - 范围内的运算符 - 的含义已经在其他答案中进行了描述,但我想补充一下人们使用它的原因。

意思是“从全局命名空间中取名,而不是其他任何东西”。但为什么需要明确拼写?

用例 - 命名空间冲突

如果在全局命名空间和本地/嵌套命名空间中具有相同的名称,则将使用本地命名空间。因此,如果您想要全局的,请将其添加到::前面。这个案例在@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_counerBend则不能。因此,如果您想确保m_counter保持为0,则必须检查Twist,但无需检查Bend

为了更清楚地突出这一点,可以写this->Twist向读者展示Twist是成员函数,或者写::Bend来表示Bend免费。或两者。当您进行或计划重构时,这非常有用。

答案 7 :(得分:3)

::是定义命名空间的运算符。

例如,如果您想在代码中使用cout而不提及using namespace std;,请写下:

std::cout << "test";

如果没有提到名称空间,则表示该类属于全局名称空间。

答案 8 :(得分:0)

“ ::”表示范围解析运算符。 可以在两个不同的类中定义具有相同名称的函数/方法。要访问特定类范围的方法,请使用解析运算符。