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


411

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

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

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

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

typedef ::config::set ConfigSet;

7
Не думаю, что это ответ, поэтому я прокомментирую: en.wikipedia.org/wiki/Scope_resolution_operator . В этом контексте скрытые ::средства ссылаются на переменную из глобального / анонимного пространства имен.
2010 г.,

Ответы:


491

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


Какова причина для установки 2 комплекта двойных двоеточий? В этом:::Configuration::doStuff(...)
Azurespot

@NoniA. Вы спрашиваете, что делает второй набор двойных двоеточий?
FCo

1
@WyattAnderson, нет 1-й сет. Я думаю, что я понимаю, что ::промежуточные два термина относятся к пространству имен или классу и его члену. Но как насчет 1-го?
Azurespot

6
@Azurespot - это то, о чем спрашивает OP, на этот вопрос отвечает этот пост. Он обязательно использует идентификатор из глобального пространства имен. Посмотрите на пример еще раз
HungryWolf

193

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

Пример:

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

123

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

/path/to/executable

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

::std::cout

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

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

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

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

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

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

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

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

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

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


8
+1 за хорошую аналогию. аналогии почти не используются в качестве учебного пособия.
Тревор Бойд Смит

38

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

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

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

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

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

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

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

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


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. Это более понятно?
Klaim

17

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

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

например:

::doMyGlobalFunction();


10

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

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

10

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

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

Вариант использования - конфликт пространства имен

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


5

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

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

std::cout << "test";

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


1

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.