Qual è il significato del doppio punto preposto "::"?


411

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

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

e non so cosa significhi esattamente il doppio colon anteposto al nome della classe. Senza di ciò leggerei: la dichiarazione di tmpCocome puntatore a un oggetto della classe Configuration... ma il doppio colon anteposto mi confonde.

Ho anche trovato:

typedef ::config::set ConfigSet;

7
Non credo che sia una risposta, quindi commenterò: en.wikipedia.org/wiki/Scope_resolution_operator . In questo contesto, il nudo ::significa riferimento alla variabile dallo spazio dei nomi globale / anonimo.
wkl,

Risposte:


491

Ciò garantisce che la risoluzione avvenga dallo spazio dei nomi globale, anziché iniziare dallo spazio dei nomi in cui ci si trova attualmente. Ad esempio, se si avessero due classi diverse chiamate Configurationcome tali:

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 ostruito da una nuova definizione all'interno di un altro spazio dei nomi, in questo caso MyApp.


Qual è la ragione per mettere 2 set di due punti? In questo:::Configuration::doStuff(...)
Azurespot

@NoniA. stai chiedendo cosa fa la seconda serie di due punti?
FCo

1
@WyattAnderson, no il 1 ° set. Penso di capire che i ::due termini intermedi si riferiscono allo spazio dei nomi o alla classe e al suo membro. Ma per quanto riguarda il primo?
Azurespot,

6
@Azurespot è quello che fa OP, questa è la domanda a cui questo post risponde. Si assicura di utilizzare l'identificatore dallo spazio dei nomi globale. Guarda di nuovo l'esempio
affamato Wolf,

193

L' ::operatore si chiama operatore di risoluzione dell'ambito e fa proprio questo, risolve l'ambito. Quindi, anteponendo un tipo-nome a questo, dice al compilatore di cercare il tipo nello spazio dei nomi globale.

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

122

Molte risposte ragionevoli già. Chiederò un'analogia che potrebbe aiutare alcuni lettori. ::funziona in modo molto simile al separatore di directory del filesystem ' /', quando cerchi nel tuo percorso un programma che desideri eseguire. Prendere in considerazione:

/path/to/executable

Questo è molto esplicito: solo un eseguibile in quella posizione esatta nella struttura del filesystem può corrispondere a questa specifica, indipendentemente dal PERCORSO in vigore. Allo stesso modo ...

::std::cout

... è ugualmente esplicito nello spazio dei nomi C ++ "albero".

In contrasto con tali percorsi assoluti, è possibile configurare buone shell UNIX (ad es. Zsh ) per risolvere percorsi relativi nella directory corrente o qualsiasi elemento nella PATHvariabile di ambiente, quindi se PATH=/usr/bin:/usr/local/bin, e si fosse "in" /tmp, quindi ...

X11/xterm

... correrebbe felice /tmp/X11/xtermse trovato, altro /usr/bin/X11/xterm, altro /usr/local/bin/X11/xterm. Allo stesso modo, supponiamo che tu fossi in uno spazio dei nomi chiamato Xe avessi un " using namespace Y" attivo, quindi ...

std::cout

... potrebbe essere trovato in qualsiasi ::X::std::cout, ::std::cout, ::Y::std::cout, ed eventualmente in altri luoghi a causa di ricerca argomento-dipendente (ADL, alias Koenig). Quindi, ::std::coutè solo esplicito esattamente su quale oggetto intendi, ma per fortuna nessuno nella loro mente giusta creerebbe mai la propria classe / struttura o spazio dei nomi chiamato " std", né qualsiasi cosa chiamata " cout", quindi in pratica usare solo std::coutva bene.

Differenze degne di nota :

1) le shell tendono a usare la prima corrispondenza usando l'ordinamento in PATH, mentre C ++ dà un errore di compilatore quando sei stato ambiguo.

2) In C ++, i nomi senza alcun ambito iniziale possono essere abbinati nello spazio dei nomi corrente, mentre la maggior parte delle shell UNIX lo fa solo se si inserisce .il file PATH.

3) C ++ cerca sempre nello spazio dei nomi globale (come avere /implicitamente il tuo PATH).

Discussione generale su spazi dei nomi e spiegazione dei simboli

L'utilizzo di ::abc::def::..."percorsi" assoluti a volte può essere utile per isolarti da qualsiasi altro spazio dei nomi che stai utilizzando, parte di ma in realtà non ha il controllo sul contenuto di, o anche altre librerie che utilizza anche il codice client della tua biblioteca. D'altra parte, ti abbina anche più strettamente alla posizione "assoluta" esistente del simbolo e perdi i vantaggi della corrispondenza implicita negli spazi dei nomi: meno accoppiamento, mobilità più semplice del codice tra spazi dei nomi e codice sorgente più conciso e leggibile .

Come per molte cose, è un atto di bilanciamento. I C ++ standard puts un sacco di identificatori ai sensi std::che sono meno "unico" che cout, che i programmatori possono utilizzare 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 maggiore di utilizzare gli stessi identificatori degli autori che generalmente non sono consapevoli 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 c'è stato un uso pesante di using namespaces: la cosa peggiore che puoi fare in questo spazio è consentireusing namespaceè nelle intestazioni per sfuggire agli ambiti delle intestazioni, in modo tale che una quantità arbitrariamente grande di codice client diretto e indiretto non è in grado di prendere le proprie decisioni su quali spazi dei nomi usare e su come gestire le ambiguità.

Quindi, un leader ::è uno strumento nella casella degli strumenti del programmatore C ++ per chiarire attivamente uno scontro noto e / o eliminare la possibilità di future ambiguità ....


8
+1 per una buona analogia. le analogie non vengono usate quasi abbastanza dall'IMO come strumento di insegnamento.
Trevor Boyd Smith,

38

::è 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è uno spazio dei nomi (nell'ambito globale o un ambito esterno rispetto a quello corrente) ed thingè un tipo , una funzione , un oggetto o uno spazio dei nomi nidificato ;
  • someè una classe disponibile nell'ambito corrente ed thingè un oggetto , una funzione o un tipo membro della someclasse;
  • in una funzione membro di classe , somepuò essere un tipo base del tipo corrente (o il tipo corrente stesso) ed thingè quindi un membro di questa classe, un tipo , una funzione o un oggetto .

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

Quindi, tornando al tuo esempio, ::thingpuò essere solo qualcosa nell'ambito globale: un tipo, una funzione, un oggetto o uno spazio dei nomi.

Il modo in cui lo usi suggerisce (usato in una dichiarazione del puntatore) che è un tipo nell'ambito globale.

Spero che questa risposta sia abbastanza completa e corretta per aiutarti a capire la risoluzione dell'ambito.


2
@obounaim Considera questo codice liveworkspace.org/code/3Wabw0$5 class some { protected: int thing; }; class some_ext : public some { float thing; void action(){ some::thing = 42; thing = 666; } }; Ecco someuna classe base di some_exte quando scrivi some::thingnelle funzioni membro di some_ext, significa che l' thingoggetto è nel tipo base some. Senza some::, thingda solo significa l' thingambito più vicino, cioè some_ext::thing. È più chiaro?
Klaim

17

:: è usato per collegare qualcosa (una variabile, una funzione, una classe, un typedef ecc ...) a uno spazio dei nomi o a una classe.

se prima non esisteva il lato sinistro ::, sottolinea il fatto che si sta utilizzando lo spazio dei nomi globale.

per esempio:

::doMyGlobalFunction();


10

il suo operatore di risoluzione dell'ambito chiamato, Un nome globale nascosto può essere indicato utilizzando l'operatore di risoluzione dell'ambito ::
Ad esempio;

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

10

(Questa risposta è principalmente per i googler, perché OP ha già risolto il suo problema.) Il significato di anteposto ::- operatore di risoluzione dell'ambito - è stato descritto in altre risposte, ma vorrei aggiungere perché le persone lo usano.

Il significato è "prendere il nome dallo spazio dei nomi globale, non altro". Ma perché questo dovrebbe essere scritto esplicitamente?

Caso d'uso: scontro tra namespace

Quando hai lo stesso nome nello spazio dei nomi globale e nello spazio dei nomi locale / nidificato, verrà utilizzato quello locale. Quindi, se si desidera quello globale, anteporre a ::. Questo caso è stato descritto nella risposta di @Wyatt Anderson, si prega di vedere il suo esempio.

Caso d'uso: enfatizza la funzione non membro

Quando si scrive una funzione membro (un metodo), le chiamate a un'altra funzione membro e le chiamate a funzioni non membro (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 succedere che Twistsia una funzione membro di classe della sorella A, ed Bendè una funzione gratuita. Cioè, Twistpuò usare e modificare m_counere Bendnon può. Quindi, se vuoi assicurarti che m_counterrimanga 0, devi controllare Twist, ma non devi controllare Bend.

Quindi, per far risaltare questo aspetto più chiaramente, si può scrivere this->Twistper mostrare al lettore che Twistè una funzione membro o scrivere ::Bendper mostrare che Bendè gratuito. O entrambi. Questo è molto utile quando stai facendo o pianificando un refactoring.


5

:: è un operatore per la definizione dello spazio dei nomi.

Ad esempio, se vuoi usare cout senza menzionare using namespace std;nel tuo codice scrivi questo:

std::cout << "test";

Quando non viene menzionato nessuno spazio dei nomi, si dice che la classe appartiene allo spazio dei nomi globale.


1

"::" rappresenta l'operatore di risoluzione dell'ambito. Funzioni / metodi con lo stesso nome possono essere definiti in due classi diverse. Per accedere ai metodi di un operatore di risoluzione ambito ambito particolare viene utilizzato.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.