Jakie jest znaczenie podwójnego dwukropka „::”?

410

Znalazłem ten wiersz kodu w klasie, którą muszę zmodyfikować:

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

i nie wiem, co dokładnie oznacza podwójny dwukropek poprzedzony nazwą klasy. Bez tego czytałbym: deklaracja tmpCojako wskaźnik do obiektu klasy Configuration... ale poprzedzony podwójny dwukropek myli mnie.

Znalazłem też:

typedef ::config::set ConfigSet;
rmbianchi
źródło
7
Naprawdę nie uważam, że to odpowiedź, więc skomentuję: en.wikipedia.org/wiki/Scope_resolution_operator . W tym kontekście naga ::oznacza odwołanie do zmiennej z globalnej / anonimowej przestrzeni nazw.
wkl

Odpowiedzi:

490

Zapewnia to, że rozpoznawanie odbywa się z globalnej przestrzeni nazw, zamiast zaczynać od przestrzeni nazw, w której się obecnie znajdujesz. Na przykład, jeśli masz dwie różne klasy nazywane Configurationjako takie:

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(...)
    }
}

Zasadniczo umożliwia przejście do globalnej przestrzeni nazw, ponieważ w tym przypadku twoje imię może zostać zablokowane przez nową definicję w innej przestrzeni nazw MyApp.

Wyatt Anderson
źródło
Jaki jest powód umieszczenia 2 zestawów podwójnych dwukropków? W tym:::Configuration::doStuff(...)
Azurespot
@NoniA. pytasz, co robi drugi zestaw podwójnych dwukropków?
FCo
1
@WyattAnderson, nie 1. zestaw. Wydaje mi się, że rozumiem, że te ::dwa terminy odnoszą się do przestrzeni nazw lub klasy i jej członka. Ale co z pierwszym?
Azurespot
6
@Azurespot o to pyta OP, na to pytanie odpowiada ten post. Zapewnia użycie identyfikatora z globalnej przestrzeni nazw. Spójrzmy jeszcze raz na przykład
głodny Wilk
193

::Operator nazywa operator zakres rozdzielczości i właśnie to robi, to rozwiązuje zakres. Tak więc, poprzedzając to nazwą typu, informuje kompilator, aby szukał w globalnej przestrzeni nazw dla typu.

Przykład:

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;
}
Sok Moo
źródło
122

Wiele rozsądnych odpowiedzi już. Wprowadzę analogię, która może pomóc niektórym czytelnikom. ::działa bardzo podobnie do separatora katalogów systemu plików ' /' podczas wyszukiwania ścieżki w poszukiwaniu programu, który chcesz uruchomić. Rozważać:

/path/to/executable

Jest to bardzo wyraźne - tylko plik wykonywalny w tej dokładnej lokalizacji w drzewie systemu plików może pasować do tej specyfikacji, niezależnie od obowiązującej PATH. Podobnie...

::std::cout

... jest równie wyraźne w „drzewie” przestrzeni nazw C ++.

Kontrastując z takimi ścieżkami bezwzględnymi, możesz skonfigurować dobre powłoki UNIX (np. Zsh ), aby rozpoznawać ścieżki względne w bieżącym katalogu lub dowolnym elemencie PATHzmiennej środowiskowej, więc jeśli PATH=/usr/bin:/usr/local/bini byłeś „w” /tmp, to ...

X11/xterm

... z radością uciekłby, /tmp/X11/xtermgdyby został znaleziony /usr/bin/X11/xterm, inaczej /usr/local/bin/X11/xterm. Podobnie, powiedz, że byłeś w przestrzeni nazwanej Xi miałeś using namespace Yefekt „ ”, a następnie ...

std::cout

... można znaleźć w każdym z ::X::std::cout, ::std::cout, ::Y::std::couti ewentualnie innych miejsc ze względu na odnośnika argumentu zależne (ADL, aka Koenig odnośników). Tak więc, tylko ::std::coutjest naprawdę jasne, co dokładnie masz na myśli, ale na szczęście nikt przy zdrowych zmysłach nigdy nie stworzyłby własnej klasy / struktury lub przestrzeni nazw o nazwie „ std”, ani niczego zwanego „ cout”, więc w praktyce używanie tylko std::coutjest w porządku.

Godne uwagi różnice :

1) powłoki zwykle używają pierwszego dopasowania przy użyciu kolejności PATH, podczas gdy C ++ daje błąd kompilatora, gdy jesteś niejednoznaczny.

2) W C ++, nazwy bez jakiejkolwiek prowadzącej zakresie mogą być dopasowane w bieżącym obszarze nazw, podczas gdy większość muszle UNIX zrobić tylko, że jeśli umieścić .w PATH.

3) C ++ zawsze przeszukuje globalną przestrzeń nazw (np. /Pośrednio twoją PATH).

Ogólna dyskusja na temat przestrzeni nazw i jawności symboli

Używanie absolutnych ::abc::def::...„ścieżek” może czasem być przydatne do odizolowania cię od innych używanych przestrzeni nazw, które są częścią, ale tak naprawdę nie mają kontroli nad zawartością, a nawet innymi bibliotekami, z których korzysta także kod klienta twojej biblioteki. Z drugiej strony, bardziej ciasno łączy się z istniejącą „bezwzględną” lokalizacją symbolu i brakuje ci zalet niejawnego dopasowywania w przestrzeniach nazw: mniej sprzężenia, łatwiejsza mobilność kodu między przestrzeniami nazw i bardziej zwięzły, czytelny kod źródłowy .

Jak w przypadku wielu rzeczy, jest to działanie równoważące. C ++ standard stawia wiele identyfikatorów pod std::które są mniej „unikalne” niż cout, że programiści mogą wykorzystać na coś zupełnie innego w kodzie (np merge, includes, fill, generate, exchange, queue, toupper, max). Dwie niepowiązane niestandardowe biblioteki mają znacznie większą szansę na użycie tych samych identyfikatorów, ponieważ autorzy są na ogół nieświadomi siebie nawzajem lub mniej. A biblioteki - w tym biblioteka C ++ Standard - z czasem zmieniają swoje symbole. Wszystko to potencjalnie tworzy dwuznaczność podczas ponownej kompilacji starego kodu, szczególnie gdy często używa się using namespaces: najgorszą rzeczą, jaką możesz zrobić w tym miejscu, jest zezwolenieusing namespacew nagłówkach, aby uciec przed zasięgami nagłówków, tak że arbitralnie duża ilość bezpośredniego i pośredniego kodu klienta nie jest w stanie podejmować własnych decyzji, których przestrzeni nazw użyć i jak zarządzać niejednoznacznościami.

Tak więc wiodącym ::jest jedno narzędzie w zestawie narzędzi programisty C ++, które aktywnie ujednoznacznia znane zderzenie i / lub eliminuje możliwość niejasności w przyszłości ...

Tony Delroy
źródło
8
+1 za dobrą analogię. analogie nie są wykorzystywane wystarczająco blisko IMO jako narzędzia dydaktycznego.
Trevor Boyd Smith
38

::jest operatorem rozdzielczości zakresu. Służy do określania zakresu czegoś.

Na przykład ::sam jest zasięgiem globalnym, poza wszystkimi innymi przestrzeniami nazw.

some::thing można interpretować na jeden z następujących sposobów:

  • somejest przestrzenią nazw (w zakresie globalnym lub zewnętrznym niż bieżący) i thingjest typem , funkcją , obiektem lub zagnieżdżoną przestrzenią nazw ;
  • somejest klasa dostępne w aktualnym zakresie i thingjest przedmiotem element , działanie lub typu z someklasy;
  • w funkcji członka klasy , somemoże być typem podstawowym bieżącego typu (lub samego bieżącego typu), a thingnastępnie jest jednym członkiem tej klasy, typem , funkcją lub obiektem .

Możesz także mieć zakres zagnieżdżony, jak w some::thing::bad. Tutaj każda nazwa może być typem, obiektem lub przestrzenią nazw. Ponadto ostatni bad, może również być funkcją. Inne nie mogły, ponieważ funkcje nie mogą ujawnić niczego w swoim wewnętrznym zakresie.

Wracając do twojego przykładu, ::thingmoże być tylko czymś w zakresie globalnym: typ, funkcja, obiekt lub przestrzeń nazw.

Sposób użycia sugeruje (używany w deklaracji wskaźnika), że jest to typ w zakresie globalnym.

Mam nadzieję, że ta odpowiedź jest kompletna i wystarczająco poprawna, aby pomóc Ci zrozumieć rozdzielczość zakresu.

Klaim
źródło
2
@obounaim Rozważ ten kod liveworkspace.org/code/3Wabw0$5 class some { protected: int thing; }; class some_ext : public some { float thing; void action(){ some::thing = 42; thing = 666; } }; Oto somepodstawowa klasa, some_exta kiedy piszesz some::thingdo funkcji składowych some_ext, oznacza to thingobiekt w typie podstawowym some. Bez some::, thingsam oznacza to thingw najbliższym zakresie, to znaczy some_ext::thing. Czy to jest bardziej jasne?
Klaim
17

:: służy do łączenia czegoś (zmiennej, funkcji, klasy, typedef itp.) z przestrzenią nazw lub klasą.

jeśli wcześniej nie było lewej strony ::, oznacza to, że używasz globalnej przestrzeni nazw.

na przykład:

::doMyGlobalFunction();

Stephane Rolland
źródło
10

zwany operatorem rozpoznawania zakresu, do ukrytej nazwy globalnej można się odwoływać za pomocą operatora rozpoznawania zakresu:
na przykład;

int x;
void f2()
{
   int x = 1; // hide global x
   ::x = 2; // assign to global x
   x = 2; // assign to local x
   // ...
}
Mustafa Ekici
źródło
10

(Ta odpowiedź jest głównie dla pracowników Google, ponieważ OP już rozwiązał swój problem.) Znaczenie wcześniejszego ::- operator resulution zakresu - zostało opisane w innych odpowiedziach, ale chciałbym dodać, dlaczego ludzie go używają.

Oznacza to: „weź nazwę z globalnej przestrzeni nazw, a nie cokolwiek innego”. Ale dlaczego miałoby to być wyrażone wprost?

Używaj kolizji nazw i nazw

Jeśli masz taką samą nazwę w globalnej przestrzeni nazw i w lokalnej / zagnieżdżonej przestrzeni nazw, używana będzie lokalna. Więc jeśli chcesz globalny, dodaj go:: . Ten przypadek został opisany w odpowiedzi @Wyatt Anderson, proszę zobaczyć jego przykład.

Przypadek użycia - podkreśl funkcję nie będącą członkiem

Kiedy piszesz funkcję członka (metodę), wywołania innej funkcji członka i wywołania funkcji nie będących członkami (bezpłatnych) wyglądają podobnie:

class A {
   void DoSomething() {
      m_counter=0;
      ...
      Twist(data); 
      ...
      Bend(data);
      ...
      if(m_counter>0) exit(0);
   }
   int m_couner;
   ...
}

Ale może się zdarzyć, że Twistjest to siostrzana funkcja klasy Ai Bendjest funkcją bezpłatną. Oznacza to, że Twistmożna używać i modyfikować, m_counera Bendnie można. Więc jeśli chcesz upewnić się, że m_counterpozostaje 0, musisz to sprawdzić Twist, ale nie musisz tego sprawdzaćBend .

Aby wyrazić to wyraźniej, można albo napisać, this->Twistaby wskazać czytelnikowi, który Twistjest funkcją składową, albo napisać, ::Bendaby pokazać, że Bendjest wolny. Lub obie. Jest to bardzo przydatne, gdy robisz lub planujesz refaktoryzację.

Rumak
źródło
5

:: jest operatorem definiującym przestrzeń nazw.

Na przykład, jeśli chcesz użyć cout bez wzmianki using namespace std;w kodzie, napisz:

std::cout << "test";

Gdy nie wspomniano o przestrzeni nazw, mówi się, że klasa należy do globalnej przestrzeni nazw.

Vladimir Ivanov
źródło
1

„::” reprezentuje operator rozdzielczości zakresu. Funkcje / metody o tej samej nazwie można zdefiniować w dwóch różnych klasach. Aby uzyskać dostęp do metod określonego zakresu klasy, używany jest operator rozdzielczości.

Vaman Acharya
źródło