Quelle est la signification du double colon ajouté «::»?

411

J'ai trouvé cette ligne de code dans une classe que je dois modifier:

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

et je ne sais pas ce que signifie exactement le double deux-points ajouté au nom de la classe. Sans cela, je lirais: déclaration de tmpCocomme pointeur sur un objet de la classe Configuration... mais le double deux points ajouté me confond.

J'ai aussi trouvé:

typedef ::config::set ConfigSet;
rmbianchi
la source
7
Je ne pense pas vraiment que ce soit une réponse, alors je commenterai: en.wikipedia.org/wiki/Scope_resolution_operator . Dans ce contexte, les ::moyens nus référencent la variable de l'espace de noms global / anonyme.
wkl

Réponses:

491

Cela garantit que la résolution se produit à partir de l'espace de noms global, au lieu de commencer à l'espace de noms dans lequel vous vous trouvez actuellement. Par exemple, si vous aviez deux classes différentes appelées Configurationcomme telles:

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

Fondamentalement, il vous permet de parcourir jusqu'à l'espace de noms global car votre nom peut être assailli par une nouvelle définition dans un autre espace de noms, dans ce cas MyApp.

Wyatt Anderson
la source
Quelle est la raison de mettre 2 jeux de deux points? Dans ceci:::Configuration::doStuff(...)
Azurespot
@NoniA. demandez-vous ce que fait le deuxième ensemble de deux points?
FCo
1
@WyattAnderson, pas le 1er set. Je pense que je comprends que les ::deux termes intermédiaires se réfèrent à l'espace de noms ou à la classe et à son membre. Mais qu'en est-il du 1er?
Azurespot
6
@Azurespot c'est ce que OP demande, c'est la question à laquelle ce message répond. Il s'assure d'utiliser l'identifiant de l'espace de noms global. Regardez à nouveau l'exemple
hungryWolf
193

L' ::opérateur est appelé opérateur de résolution de portée et fait exactement cela, il résout la portée. Ainsi, en préfixant un nom de type avec ceci, il indique à votre compilateur de rechercher dans le nom global le type.

Exemple:

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;
}
Moo-Juice
la source
122

Beaucoup de réponses raisonnables déjà. Je vais apporter une analogie qui pourrait aider certains lecteurs. ::fonctionne un peu comme le séparateur de répertoires du système de fichiers ' /', lorsque vous recherchez dans votre chemin un programme que vous souhaitez exécuter. Considérer:

/path/to/executable

Ceci est très explicite - seul un exécutable à cet emplacement exact dans l'arborescence du système de fichiers peut correspondre à cette spécification, quel que soit le PATH en vigueur. De même...

::std::cout

... est également explicite dans "l'arborescence" de l'espace de noms C ++.

Contrairement à ces chemins absolus, vous pouvez configurer de bons shells UNIX (par exemple zsh ) pour résoudre les chemins relatifs sous votre répertoire actuel ou n'importe quel élément de votre PATHvariable d'environnement, donc si PATH=/usr/bin:/usr/local/bin, et vous étiez "dans" /tmp, alors ...

X11/xterm

... courrait avec plaisir /tmp/X11/xterms'il était trouvé, sinon /usr/bin/X11/xterm, sinon /usr/local/bin/X11/xterm. De même, supposons que vous vous trouviez dans un espace de noms appelé X, et que vous aviez un " using namespace Y" en vigueur, alors ...

std::cout

... pourrait être trouvé dans l' un des ::X::std::cout, ::std::cout, ::Y::std::coutet éventuellement d' autres endroits en raison de recherche dépendant de l' argument (ADL, alias Koenig recherche). Donc, seul ::std::coutest vraiment explicite exactement l'objet que vous voulez dire, mais heureusement, personne sensé ne créerait jamais sa propre classe / structure ou espace de noms appelé " std", ni quoi que ce soit appelé " cout", donc en pratique, utiliser std::coutest très bien.

Différences notables :

1) les shells ont tendance à utiliser la première correspondance en utilisant l'ordre dans PATH, tandis que C ++ donne une erreur de compilation lorsque vous avez été ambigu.

2) En C ++, les noms sans portée principale peuvent être mis en correspondance dans l'espace de noms actuel, tandis que la plupart des shells UNIX ne le font que si vous les mettez .dans le PATH.

3) C ++ recherche toujours l'espace de noms global (comme avoir /implicitement votre PATH).

Discussion générale sur les espaces de noms et l'explicitation des symboles

L'utilisation de ::abc::def::..."chemins" absolus peut parfois être utile pour vous isoler de tout autre espace de noms que vous utilisez, qui fait partie, mais n'a pas vraiment de contrôle sur le contenu, ni même d'autres bibliothèques que le code client de votre bibliothèque utilise également. D'autre part, il vous couple également plus étroitement à l'emplacement "absolu" existant du symbole, et vous manquez les avantages de la correspondance implicite dans les espaces de noms: moins de couplage, mobilité plus facile du code entre les espaces de noms et code source plus concis et lisible .

Comme pour beaucoup de choses, c'est un équilibre. Les C ++ standard puts beaucoup d'identificateurs sous std::qui sont moins « unique » que cout, que les programmeurs peuvent utiliser pour quelque chose de complètement différent dans leur code (par exemple merge, includes, fill, generate, exchange, queue, toupper, max). Deux bibliothèques non standard non apparentées ont beaucoup plus de chances d'utiliser les mêmes identifiants car les auteurs ne se connaissent généralement pas ou moins. Et les bibliothèques - y compris la bibliothèque C ++ Standard - changent leurs symboles au fil du temps. Tout cela crée potentiellement une ambiguïté lors de la recompilation de l'ancien code, en particulier lorsqu'il y a eu une utilisation intensive de using namespaces: la pire chose que vous puissiez faire dans cet espace est de permettreusing namespaces dans les en-têtes pour échapper à la portée des en-têtes, de sorte qu'une quantité arbitrairement importante de code client direct et indirect ne peut pas prendre ses propres décisions concernant les espaces de noms à utiliser et comment gérer les ambiguïtés.

Ainsi, un leader ::est un outil dans la boîte à outils du programmeur C ++ pour lever activement l'ambiguïté d'un conflit connu et / ou éliminer la possibilité d'une ambiguïté future ...

Tony Delroy
la source
8
+1 pour une bonne analogie. les analogies ne sont pas assez utilisées comme IMO comme outil d'enseignement.
Trevor Boyd Smith,
38

::est l'opérateur de résolution de la portée. Il est utilisé pour spécifier la portée de quelque chose.

Par exemple, ::seule est la portée globale, en dehors de tous les autres espaces de noms.

some::thing peut être interprété de l'une des manières suivantes:

  • someest un espace de noms (dans la portée globale ou une portée extérieure à la portée actuelle) et thingest un type , une fonction , un objet ou un espace de noms imbriqué ;
  • someest une classe disponible dans la portée actuelle et thingest un objet membre , une fonction ou un type de la someclasse;
  • dans une fonction membre de classe , somepeut être un type de base du type actuel (ou le type actuel lui-même) et thingest alors un membre de cette classe, un type , une fonction ou un objet .

Vous pouvez également avoir une portée imbriquée, comme dans some::thing::bad. Ici, chaque nom peut être un type, un objet ou un espace de noms. De plus, le dernier,, badpourrait également être une fonction. Les autres ne pouvaient pas, car les fonctions ne peuvent rien exposer dans leur portée interne.

Donc, revenons à votre exemple, ::thingne peut être que quelque chose dans la portée globale: un type, une fonction, un objet ou un espace de noms.

La façon dont vous l'utilisez suggère (utilisé dans une déclaration de pointeur) qu'il s'agit d'un type dans la portée globale.

J'espère que cette réponse est complète et suffisamment correcte pour vous aider à comprendre la résolution de la portée.

Klaim
la source
2
@obounaim Considérez ce code liveworkspace.org/code/3Wabw0$5 class some { protected: int thing; }; class some_ext : public some { float thing; void action(){ some::thing = 42; thing = 666; } }; Voici someune classe de base de some_extet lorsque vous écrivez some::thingdans les fonctions membres de some_ext, cela signifie l' thingobjet dans le type de base some. Sans some::, thingseul signifie le thingplus proche, c'est-à-dire some_ext::thing. Est-ce plus clair?
Klaim
17

:: est utilisé pour lier quelque chose (une variable, une fonction, une classe, un typedef etc ...) à un espace de noms, ou à une classe.

s'il n'y a pas de gauche avant ::, cela souligne le fait que vous utilisez l'espace de noms global.

par exemple:

::doMyGlobalFunction();

Stéphane Rolland
la source
10

son opérateur de résolution de portée appelé, Un nom global caché peut être référencé en utilisant l'opérateur de résolution de portée ::
Par exemple;

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

(Cette réponse s'adresse principalement aux googleurs, car OP a déjà résolu son problème.) :: opérateur de résolution de portée ajouté a été décrit dans d'autres réponses, mais j'aimerais ajouter pourquoi les gens l'utilisent.

La signification est "prendre le nom de l'espace de noms global, pas autre chose". Mais pourquoi cela devrait-il être orthographié explicitement?

Cas d'utilisation - conflit d'espace de noms

Lorsque vous avez le même nom dans l'espace de noms global et dans l'espace de noms local / imbriqué, le nom local sera utilisé. Donc, si vous voulez le global, ajoutez-le avec ::. Ce cas a été décrit dans la réponse de @Wyatt Anderson, veuillez voir son exemple.

Cas d'utilisation - souligner la fonction non membre

Lorsque vous écrivez une fonction membre (une méthode), les appels à une autre fonction membre et les appels à des fonctions non membres (gratuites) se ressemblent:

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

Mais il peut arriver que ce Twistsoit une fonction membre de classe sœur A, et Bendsoit une fonction libre. Autrement dit, Twistpeut utiliser et modifier m_couneret Bendne peut pas. Donc, si vous voulez vous assurer que m_counterreste 0, vous devez vérifier Twist, mais vous n'avez pas besoin de vérifierBend .

Donc, pour que cela ressorte plus clairement, on peut soit écrire this->Twistpour montrer au lecteur qui Twistest une fonction membre, soit écrire ::Bendpour montrer que Bendc'est gratuit. Ou les deux. Ceci est très utile lorsque vous effectuez ou planifiez une refactorisation.

Coursier
la source
5

:: est un opérateur de définition de l'espace de noms.

Par exemple, si vous souhaitez utiliser cout sans mentionner using namespace std;dans votre code, vous écrivez ceci:

std::cout << "test";

Quand aucun espace de noms n'est mentionné, il est dit que la classe appartient à l'espace de noms global.

Vladimir Ivanov
la source
1

"::" représente l'opérateur de résolution de portée. Les fonctions / méthodes qui portent le même nom peuvent être définies dans deux classes différentes. Pour accéder aux méthodes d'un opérateur de résolution d'étendue de classe particulier est utilisé.

Vaman Acharya
la source