Яке значення попередньо подвійної двокрапки "::"?


410

Я знайшов цей рядок коду в класі, який я повинен змінити:

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

і я не знаю, що саме означає подвійну двокрапку, прикинуту до назви класу. Без цього я б читав: декларація tmpCoяк вказівник на об’єкт класу Configuration... але попередньо подвійне двокрап'я мене бентежить.

Я також виявив:

typedef ::config::set ConfigSet;

7
Не дуже відчуваю, що це відповідь, тому я прокоментую: en.wikipedia.org/wiki/Scope_resolution_operator . У цьому контексті "гола" ::означає посилання на змінну з глобального / анонімного простору імен.
wkl

Відповіді:


490

Це гарантує, що роздільна здатність виникає з глобальної простори імен, а не починається з простору імен, в якій ви зараз перебуваєте. Наприклад, якщо у вас було два різних класи, викликані 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 ось що задає ОП, саме на це питання відповідає ця публікація. Він обов'язково використовує ідентифікатор із глобальної простору імен. Подивіться на приклад ще раз
голодний Вовк

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

122

Вже багато обґрунтованих відповідей. Я докладу аналогію, яка може допомогти деяким читачам. ::працює дуже добре, як роздільник каталогів файлової системи ' /', під час пошуку вашого шляху для програми, яку ви хочете запустити. Поміркуйте:

/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 namespaces у заголовках, щоб уникнути діапазону заголовків, таким чином, що довільно велика кількість прямого та непрямого коду клієнта не може самостійно приймати рішення щодо того, які простори імен використовувати та як керувати двозначностями.

Отже, провідним ::є один із інструментів у програмі інструментів програміста 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. Чи зрозуміліше?
Клаїм

17

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

якщо раніше немає лівої сторони ::, це підкреслює факт використання глобального простору імен.

наприклад:

::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

(Ця відповідь здебільшого стосується googlers, тому що ОР вже вирішив свою проблему.) Сенс ::попередженого - оператор результатів діапазону - описаний в інших відповідях, але я хотів би додати, чому люди його використовують.

Сенс - "взяти ім’я з глобального простору імен, не більше нічого". Але навіщо це потрібно чітко писати?

Використовуйте зіткнення простору імен

Якщо у вас є те саме ім'я в глобальній просторі імен та в локальному / вкладеному просторі імен, буде використано локальне. Тож якщо ви хочете глобальну, додайте її до цього ::. Цей випадок був описаний у відповіді @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.