web-dev-qa-db-fra.com

Quelle est la signification du double-colon préposé "::"?

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 tmpCo en tant que pointeur sur un objet de la classe Configuration..., mais le double deux-points préfixé me perturbe.

J'ai aussi trouvé:

typedef ::config::set ConfigSet;
370
rmbianchi

Cela garantit que la résolution s'effectue à partir de l'espace de noms global, au lieu de commencer à l'espace de noms actuel. Par exemple, si vous aviez deux classes différentes appelées Configuration en tant que 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(...)
    }
}

En gros, cela vous permet de parcourir jusqu’à l’espace de noms global car votre nom risque d’être obstrué par une nouvelle définition dans un autre espace de noms, dans ce cas MyApp.

444
Wyatt Anderson

L'opérateur :: s'appelle l'opérateur de résolution d'étendue et fait exactement cela, il résout l'étendue. Donc, en préfixant un nom de type avec cela, il indique à votre compilateur de rechercher le type dans l'espace de noms global.

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;
}
179
Moo-Juice

Beaucoup de réponses raisonnables déjà. J'interviendrai avec une analogie qui pourrait aider certains lecteurs. :: fonctionne beaucoup 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'arbre" 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 de votre répertoire actuel ou n'importe quel élément de votre variable d'environnement PATH, donc si PATH=/usr/bin:/usr/local/bin et que vous étiez "dans" /tmp, alors ...

X11/xterm

... serait heureux d'exécuter /tmp/X11/xterm s'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 utilisiez un "using namespace Y", puis ...

std::cout

... pourrait être trouvé dans n'importe lequel de ::X::std::cout, ::std::cout, ::Y::std::cout, et peut-être à d'autres endroits en raison de recherche dépendante de l'argument (ADL, également appelée recherche Koenig) ) Ainsi, seul ::std::cout précise vraiment de quel objet vous parlez, mais heureusement, personne de son esprit ne créerait jamais sa propre classe/structure ou espace de nom appelé "std", ni rien de ce qui s'appelle "cout ", donc dans la pratique, n'utilisez que std::cout.

Différences notables :

1) Les shells ont tendance à utiliser la première correspondance en utilisant l'ordre dans PATH, alors que C++ génère 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 nom actuel, alors que la plupart des shells UNIX ne le font que si vous mettez . dans PATH.

3) C++ cherche toujours dans l’espace de noms global (comme avoir / implicitement votre PATH).

Discussion générale sur les espaces de noms et le caractère explicite des symboles

Utiliser ::abc::def::... absolu _ "chemins" peut parfois être utile pour vous isoler de tout autre espace de nom que vous utilisez, dont vous n'avez pas vraiment le contrôle sur le contenu, ou même d'autres bibliothèques que le code client de votre bibliothèque. les usages. D'autre part, il vous associe également plus étroitement à l'emplacement "absolu" existant du symbole, et vous perdez 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 acte d'équilibre. Le standard C++ place sous std:: de nombreux identifiants moins "uniques" que cout, que les programmeurs pourraient 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 liées ont beaucoup plus de chances d'utiliser les mêmes identificateurs, 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 risque de créer une ambiguïté lors de la recompilation de vieux code, en particulier en cas d'utilisation intensive de using namespaces: la pire chose à faire dans cet espace est de permettre à using namespaces dans les en-têtes d'échapper à la portée des en-têtes, de telle sorte que une quantité arbitrairement importante de codes clients directs et indirects est incapable de prendre ses propres décisions quant aux espaces de noms à utiliser et à la manière de gérer les ambiguïtés.

Ainsi, un :: de premier plan est l'un des outils de la boîte à outils du programmeur C++ permettant de lever les ambiguïtés d'un conflit et/ou d'éliminer toute possibilité d'ambiguïté future ....

108
Tony Delroy

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

  • some est un espace de nom (dans la portée globale ou une portée externe à celle actuelle) et thing est un type, a - fonction, un objet ou un espace de noms imbriqué;
  • some est un classe disponible dans l'étendue actuelle et thing est un objet membre, fonction ou type de la classe some;
  • dans une fonction membre de classe, some peut être un type de base du type actuel (ou le type actuel lui-même) et thing est alors un membre de cette classe, un type, fonction ou objet.

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

Donc, revenons à votre exemple, ::thing ne peut être qu'un élément de 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ée 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 suffisamment complète et correcte pour vous aider à comprendre la résolution de la portée.

35
Klaim

:: 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 côté gauche avant ::, cela souligne le fait que vous utilisez l'espace de noms global.

par exemple.:

::doMyGlobalFunction();

14
Stephane Rolland

son appelé opérateur de résolution de portée, un nom global masqué peut être référencé à l’aide de 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
   // ...
}
9
Mustafa Ekici

(Cette réponse concerne principalement les googleurs, car OP a déjà résolu son problème.) La signification de :: ajouté - scope - scope resulution operator - a été décrite dans d'autres réponses, mais j'aimerais ajouter pourquoi les gens l'utilisent. .

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

Cas d'utilisation - conflit d'espace de noms

Lorsque vous avez le même nom dans un espace de noms global et dans un espace de noms local/imbriqué, le nom local est utilisé. Donc, si vous voulez la version globale, ajoutez-y ::. Ce cas a été décrit dans la réponse de @Wyatt Anderson. Veuillez voir son exemple.

Cas d'utilisation - met l'accent sur la fonction non membre

Lorsque vous écrivez une fonction membre (une méthode), les appels vers d'autres fonctions membres et les appels vers des fonctions non membres (libres) 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 Twist soit une fonction membre soeur de la classe A et que Bend soit une fonction libre. Autrement dit, Twist peut utiliser et modifier m_couner et Bend ne peut pas. Donc, si vous voulez vous assurer que m_counter reste à 0, vous devez vérifier Twist, mais vous n'avez pas besoin de vérifier Bend.

Pour mieux faire ressortir ce point, on peut écrire this->Twist afin de montrer au lecteur que Twist est une fonction membre ou écrire ::Bend pour indiquer que Bend est libre. Ou les deux. Ceci est très utile lorsque vous effectuez ou planifiez une refactorisation.

6
Steed

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

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

std::cout << "test";

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

3
Vladimir Ivanov

"::" représente l'opérateur de résolution de la portée. Les fonctions/méthodes qui ont 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 de portée de classe particulier est utilisé.

0
Vaman Acharya