В чем смысл двойного двоеточия с префиксом «::»?

344

Я нашел эту строку кода в классе, который мне нужно изменить:

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

и я не знаю, что именно означает двойной двоеточие, добавленное к имени класса. Без этого я бы прочитал: объявление tmpCo как указатель на объект класса Configuration... но добавленная двойная двоеточие смущает меня.

Я также нашел:

typedef ::config::set ConfigSet;
  • 7
    Не думаю, что это ответ, поэтому я прокомментирую: en.wikipedia.org/wiki/Scope_resolution_operator . В этом контексте naked :: means ссылается на переменную из глобального / анонимного пространства имен.
Теги:
namespaces
syntax

8 ответов

435
Лучший ответ

Это гарантирует, что разрешение происходит из глобального пространства имен, вместо того, чтобы запускаться в пространстве имен, в котором вы сейчас находитесь. Например, если у вас было два разных класса с именем 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.

  • 0
    Какова причина для установки 2 комплекта двойных двоеточий? В этом: ::Configuration::doStuff(...)
  • 0
    @NoniA. Вы спрашиваете, что делает второй набор двойных двоеточий?
Показать ещё 2 комментария
177

Оператор :: называется оператором с разрешающей способностью и делает именно это, он разрешает область действия. Таким образом, путем префикса имени типа этим, он сообщает вашему компилятору посмотреть в глобальном пространстве имен для типа.

Пример:

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

Много разумных ответов уже. Я приведу аналогию, которая может помочь некоторым читателям. :: работает так же, как разделитель каталогов файловой системы ' / ', когда вы ищите в своем пути программу, которую хотите запустить. Рассматривать:

/path/to/executable

Это очень явно - только исполняемый файл в этом точном месте в дереве файловой системы может соответствовать этой спецификации, независимо от действующей переменной PATH. Так же...

::std::cout

... одинаково явно в пространстве имен C++ "tree".

В отличие от таких абсолютных путей, вы можете настроить хорошие оболочки UNIX (например, zsh) для разрешения относительных путей в вашем текущем каталоге или в любом элементе PATH среды 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, иначе Поиск Кенига). Таким образом, only ::std::cout действительно явно указывает, какой именно объект вы имеете в виду, но, к счастью, никто в здравом уме никогда не создаст свой собственный класс/структуру или пространство имен с именем " std " или что-либо с именем " cout ", поэтому в практика использования только std::cout - это нормально.

Примечательные отличия:

1) оболочки обычно используют первое совпадение с использованием порядка в PATH, тогда как C++ выдает ошибку компилятора, когда вы неоднозначны.

2) В C++ имена без какой-либо ведущей области могут быть сопоставлены в текущем пространстве имен, в то время как большинство оболочек UNIX делают это, только если вы добавили . в PATH.

3) C++ всегда ищет глобальное пространство имен (например, имеет / неявно ваш PATH).

Общая дискуссия о пространствах имен и явности символов

Использование absolute ::abc::def::... "paths" иногда может быть полезно для изоляции вас от любых других пространств имен, которые вы используете, частично, но на самом деле не контролируете содержимое или даже другие библиотеки что код вашей библиотеки клиента также использует. С другой стороны, он также более тесно связывает вас с существующим "абсолютным" расположением символа, и вы упускаете преимущества неявного сопоставления в пространствах имен: меньшая связь, более легкая мобильность кода между пространствами имен и более лаконичный, читаемый исходный код,

Как и во многих вещах, это уравновешивание. Стандарт C++ помещает множество идентификаторов в std::, которые менее "уникальны", чем cout, которые программисты могут использовать для чего-то совершенно другого в своем коде (например, merge, includes, fill, generate, exchange, queue, toupper, max). Две несвязанные нестандартные библиотеки имеют гораздо большую вероятность использовать те же идентификаторы, что авторы обычно un- или менее осведомлены друг о друге. И библиотеки, включая стандартную библиотеку C++, со временем меняют свои символы. Все это потенциально создает неоднозначность при перекомпиляции старого кода, особенно когда интенсивно использовалось using namespace s: самое худшее, что вы можете сделать в этом пространстве, это разрешить using namespace в заголовках для экранирования областей заголовков, так что произвольно большое количество Прямой и непрямой клиентский код не может самостоятельно принимать решения о том, какие пространства имен использовать и как управлять неоднозначностями.

Таким образом, ведущий :: является одним из инструментов в наборе инструментов C++ для активной устранения неоднозначности известного столкновения и/или устранения возможности будущей неоднозначности....

  • 5
    +1 за хорошую аналогию. аналогии почти не используются в качестве учебного пособия.
34

:: - оператор разрешения области. Он использовал для определения области действия.

Например, только :: является глобальной областью, вне всех других пространств имен.

some::thing можно интерпретировать одним из следующих способов:

  • some является пространством имен (в глобальной области видимости или внешней областью, чем текущая), а thing - тип , функция, объект или вложенное пространство имен;
  • some - класс, доступный в текущей области действия, а thing - объект объекта, функции или класса some;
  • в функции члена класса, some может быть базовым типом текущего типа (или самого текущего типа) и thing является тогда одним членом этого класса, тип, функция или объект.

Вы также можете иметь вложенную область, как в some::thing::bad. Здесь каждое имя может быть типом, объектом или пространством имен. Кроме того, последняя функция bad также может быть функцией. Остальные не могли, так как функции не могут раскрывать что-либо в пределах их внутреннего объема.

Итак, вернемся к вашему примеру, ::thing может быть только чем-то в глобальной области: типом, функцией, объектом или пространством имен.

То, как вы его используете, предполагает (используется в объявлении указателя), что это тип в глобальной области.

Я надеюсь, что этот ответ будет полным и правильным, чтобы помочь вам понять разрешение области.

  • 0
    @ Клаим, я не унываю, третий пункт.
  • 2
    @obounaim Рассмотрим этот код. liveworkspace.org/code/3Wabw0$5 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 . Это более понятно?
13

:: используется для связывания чего-либо (переменной, функции, класса, typedef и т.д.) с пространством имен или с классом.

если перед :: нет левой стороны, то это подчеркивает тот факт, что вы используете глобальное пространство имен.

например:.

::doMyGlobalFunction();

9

его вызываемый оператор разрешающей области, скрытое глобальное имя можно отнести к использованию оператора разрешения области::
Например:

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

(Этот ответ в основном для гуглеров, потому что ОП уже решил свою проблему). Значение добавочного оператора :: - resulution области - было описано в других ответах, но я хотел бы добавить, почему люди его используют.

Значение "принимать имя из глобального пространства имен, а не что-нибудь еще". Но почему это должно быть написано явно?

Использовать случайное пространство имен

Если у вас есть одно и то же имя в глобальном пространстве имен и в локальном/вложенном пространстве имен, будет использоваться локальный. Поэтому, если вы хотите глобальный, добавьте его с помощью ::. Этот случай был описан в ответе @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 является бесплатным. Или оба. Это очень полезно, когда вы делаете или планируете рефакторинг.

3

:: - это оператор определения пространства имен.

Например, если вы хотите использовать cout без упоминания using namespace std; в своем коде, вы пишете это:

std::cout << "test";

Если не указано пространство имен, говорится, что класс принадлежит глобальному пространству имен.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню