Qual è il significato del doppio punto anteposto “::”?

Ho trovato questa riga di codice in una class che devo modificare:

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

e non so cosa significhi esattamente il doppio colon anteposto al nome della class. Senza di ciò leggo: dichiarazione di tmpCo come puntatore a un object della class Configuration … ma il doppio doppio anteposto mi confonde.

Ho anche trovato:

 typedef ::config::set ConfigSet; 

Ciò assicura che la risoluzione si verifichi dallo spazio dei nomi globale, invece di iniziare nello spazio dei nomi in cui ci si trova. Ad esempio, se si hanno due classi diverse chiamate Configuration quanto tale:

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

Fondamentalmente, ti permette di attraversare lo spazio dei nomi globale poiché il tuo nome potrebbe essere danneggiato da una nuova definizione all’interno di un altro spazio dei nomi, in questo caso MyApp .

L’operatore :: è chiamato operatore di risoluzione dell’ambito e fa proprio questo, risolve l’ambito. Quindi, con il prefisso di un nome-tipo con questo, dice al compilatore di cercare nello spazio dei nomi globale per il tipo.

Esempio:

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

Un sacco di risposte ragionevoli già. Farò un chip con un’analogia che potrebbe aiutare alcuni lettori. :: funziona molto come il separatore di directory del filesystem ‘ / ‘, quando si cerca il percorso per un programma che si desidera eseguire. Prendere in considerazione:

 /path/to/executable 

Questo è molto esplicito – solo un eseguibile in quella posizione esatta nell’albero del filesystem può corrispondere a questa specifica, indipendentemente dal PATH in effetti. Allo stesso modo …

 ::std::cout 

… è ugualmente esplicito nello “spazio” del namespace C ++.

A differenza di tali percorsi assoluti, è ansible configurare buone shell UNIX (ad es. Zsh) per risolvere percorsi relativi sotto qualsiasi elemento della variabile d’ambiente PATH , quindi se PATH=/usr/bin:/usr/local/bin , quindi …

 X11/xterm 

… sarebbe felice di usare /usr/bin/X11/xterm se trovato, altrimenti /usr/local/bin/X11/xterm . Allo stesso modo, dì che eri in uno spazio dei nomi chiamato X , e avevi un ” using namespace Y “, quindi …

 std::cout 

… può essere trovato in uno qualsiasi di ::X::std::cout , ::std::cout , ::Y::std::cout , e probabilmente in altri posti a causa della ricerca dipendente dall’argomento (ADL, aka Ricerca di Koenig). Quindi, solo ::std::cout è davvero esplicito su esattamente quale object intendi, ma fortunatamente nessuno sano di mente creerebbe mai la propria class / struttura o spazio dei nomi chiamato ” std “, né qualcosa chiamato ” cout “, quindi in pratica usando solo std::cout va bene.

(Una differenza degna di nota è che le shell tendono a usare la prima corrispondenza usando l’ordine in PATH , mentre C ++ dà un errore del compilatore quando sei stato ambiguo.)

Discussione generale sugli spazi dei nomi e esplicitazione dei simboli

L’utilizzo di absolute ::abc::def::... “percorsi” può a volte essere utile per isolarti da qualsiasi altro spazio dei nomi che stai usando, ma non avere realmente il controllo sul contenuto di, o anche su altre librerie utilizza anche il codice client della tua biblioteca. D’altra parte, ti accoppia anche più strettamente alla posizione “assoluta” esistente del simbolo e perdi i vantaggi della corrispondenza implicita negli spazi dei nomi: minore accoppiamento, più facile mobilità del codice tra spazi dei nomi e codice sorgente più conciso e leggibile .

Come con molte cose, è un atto di bilanciamento. Lo standard C ++ mette molti identificatori sotto std:: che sono meno “unici” di cout , che i programmatori potrebbero usare per qualcosa di completamente diverso nel loro codice (ad esempio merge , includes , fill , generate , exchange , queue , toupper , max ). Due librerie non standard non correlate hanno una probabilità molto più alta di utilizzare gli stessi identificatori di cui gli autori sono generalmente meno o meno consapevoli l’uno dell’altro. E le librerie, inclusa la libreria standard C ++, cambiano i loro simboli nel tempo. Tutto ciò potenzialmente crea ambiguità quando si ricompila il vecchio codice, in particolare quando si usa pesantemente lo using namespace dei using namespace : la cosa peggiore che si può fare in questo spazio è consentire l’ using namespace nelle intestazioni per sfuggire agli scopi delle intestazioni, così che una quantità arbitrariamente grande del codice cliente diretto e indiretto non è in grado di prendere le proprie decisioni su quali spazi dei nomi utilizzare e su come gestire le ambiguità.

Quindi, uno dei principali :: è uno strumento nella casella degli strumenti del programmatore C ++ per disambiguare triggersmente uno scontro noto e / o eliminare la possibilità di future ambiguità ….

:: è l’operatore di risoluzione dell’ambito. È usato per specificare l’ambito di qualcosa.

Ad esempio, :: solo è l’ambito globale, al di fuori di tutti gli altri spazi dei nomi.

some::thing può essere interpretato in uno dei seguenti modi:

  • some sono uno spazio dei nomi (nell’ambito globale, o un ambito esterno rispetto a quello corrente) e la thing è un tipo , una funzione , un object o uno spazio dei nomi annidato ;
  • some sono una class disponibile nell’ambito corrente e la thing è un object membro , una funzione o un tipo di some class;
  • in una funzione membro della class , some possono essere un tipo base del tipo corrente (o il tipo corrente stesso) e la thing è quindi un membro di questa class, un tipo , una funzione o un object .

Puoi anche avere scope nidificati, come in some::thing::bad . Qui ogni nome potrebbe essere un tipo, un object o uno spazio dei nomi. Inoltre, l’ultimo, bad , potrebbe anche essere una funzione. Gli altri non potrebbero, poiché le funzioni non possono esporre nulla all’interno del loro ambito interno.

Quindi, tornando al tuo esempio, ::thing può essere solo qualcosa nell’ambito globale: un tipo, una funzione, un object o un namespace.

Il modo in cui lo si utilizza suggerisce (utilizzato in una dichiarazione puntatore) che si tratta di un tipo nell’ambito globale.

Spero che questa risposta sia completa e corretta per aiutarti a comprendere la risoluzione dell’ambito.

:: è usato per colbind qualcosa (una variabile, una funzione, una class, un typedef ecc …) ad uno spazio dei nomi, o ad una class.

se non c’è il lato sinistro prima di :: , allora sottolinea il fatto che stai usando lo spazio dei nomi globale.

per esempio:

::doMyGlobalFunction();

il suo operatore di risoluzione dell’ambito chiamato, un nome globale nascosto può essere riferito a utilizzando l’operatore di risoluzione dell’oscilloscopio ::
Per esempio;

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

(Questa risposta è per lo più per i googler, perché OP ha già risolto il suo problema.) Il significato di prepended :: – scope scope resulution operator – è stato descritto in altre risposte, ma mi piacerebbe aggiungere perché le persone lo stanno usando.

Il significato è “prendi il nome dal namespace globale, non da qualsiasi altra cosa”. Ma perché questo deve essere scritto esplicitamente?

Usa caso – scontro spazio dei nomi

Quando si ha lo stesso nome nello spazio dei nomi globale e nello spazio dei nomi locale / annidato, verrà utilizzato quello locale. Quindi, se vuoi quello globale, anteponilo a :: . Questo caso è stato descritto nella risposta di @Wyatt Anderson, vedendo il suo esempio.

Usa caso – enfatizza la funzione non membro

Quando si scrive una funzione membro (un metodo), le chiamate ad altre funzioni membro e le chiamate a funzioni non associate (gratuite) si assomigliano:

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

Ma potrebbe accadere che Twist sia una funzione membro sorella della class A , e Bend è una funzione libera. Cioè, Twist può usare e modificare m_couner e Bend no. Quindi, se vuoi assicurarti che m_counter rimanga 0, devi controllare Twist , ma non devi controllare Bend .

Quindi, per farla risaltare più chiaramente, puoi scrivere this->Twist per mostrare al lettore che Twist è una funzione membro o scrivi ::Bend per mostrare che Bend è libero. O entrambi. Questo è molto utile quando stai facendo o pianificando un refactoring.

:: è un operatore di definizione dello spazio dei nomi.

Ad esempio, se si desidera utilizzare cout senza menzionare l’ using namespace std; nel tuo codice scrivi questo:

 std::cout << "test"; 

Quando non viene menzionato alcun namespace, si dice che la class appartiene al namespace globale.