В чем смысл двойного двоеточия с префиксом "::"? - PullRequest
361 голосов
/ 24 ноября 2010

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

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

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

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

typedef ::config::set ConfigSet;

Ответы [ 9 ]

431 голосов
/ 24 ноября 2010

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

176 голосов
/ 24 ноября 2010

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

Пример:

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;
}
106 голосов
/ 24 ноября 2010

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

/path/to/executable

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

::std::cout

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

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

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

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

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

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

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

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

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

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

35 голосов
/ 24 ноября 2010

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

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

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

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

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

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

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

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

14 голосов
/ 24 ноября 2010

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

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

например:.

::doMyGlobalFunction();

9 голосов
/ 11 октября 2013

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

int x;
void f2()
{
   int x = 1; // hide global x
   ::x = 2; // assign to global x
   x = 2; // assign to local x
   // ...
}
6 голосов
/ 23 октября 2013

(Этот ответ в основном предназначен для 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_couner, а Bend - нет. Поэтому, если вы хотите убедиться, что m_counter остается 0, вам нужно проверить Twist, но вам не нужно проверять Bend.

Таким образом, чтобы сделать это более четким, можно написать this->Twist, чтобы показать читателю, что Twist является функцией-членом, или написать ::Bend, чтобы показать, что Bend свободна. Или оба. Это очень полезно, когда вы делаете или планируете рефакторинг.

3 голосов
/ 24 ноября 2010

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

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

std::cout << "test";

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

0 голосов
/ 20 февраля 2019

"::" представляет оператор разрешения области.Функции / методы с одинаковым именем могут быть определены в двух разных классах.Для доступа к методам конкретного класса используется область разрешения оператора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...