¿Cuál es el significado de los dos puntos dobles "::"?

411

Encontré esta línea de código en una clase que tengo que modificar:

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

y no sé qué significa exactamente los dos puntos anteriores al nombre de la clase. Sin eso, leería: la declaración de tmpCocomo un puntero a un objeto de la clase Configuration... pero el doble colon antepuesto me confunde.

También encontré:

typedef ::config::set ConfigSet;
rmbianchi
fuente
77
Realmente no creo que sea una respuesta, así que comentaré: en.wikipedia.org/wiki/Scope_resolution_operator . En este contexto, los ::medios desnudos hacen referencia a la variable del espacio de nombres global / anónimo.
wkl

Respuestas:

491

Esto garantiza que la resolución se produzca desde el espacio de nombres global, en lugar de comenzar en el espacio de nombres en el que se encuentra actualmente. Por ejemplo, si tuviera dos clases diferentes llamadas Configurationcomo tales:

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

Básicamente, le permite atravesar el espacio de nombres global ya que su nombre podría verse afectado por una nueva definición dentro de otro espacio de nombres, en este caso MyApp.

Wyatt Anderson
fuente
¿Cuál es la razón para poner 2 juegos de dos puntos dobles? En esto:::Configuration::doStuff(...)
Azurespot
@NoniA. ¿Estás preguntando qué hace el segundo conjunto de dos puntos dobles?
FCo
1
@WyattAnderson, no el primer set. Creo que entiendo que los ::dos términos intermedios se refieren al espacio de nombres o clase y su miembro. ¿Pero qué hay del primero?
Azurespot
66
@Azurespot, eso es lo que pregunta OP, esa es la pregunta que responde esta publicación. Se asegura de usar el identificador del espacio de nombres global. Mira el ejemplo otra vez
hungryWolf
193

El ::operador se llama operador de resolución de alcance y hace exactamente eso, resuelve el alcance. Entonces, al prefijar un nombre de tipo con esto, le dice a su compilador que busque el tipo en el espacio de nombres global.

Ejemplo:

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;
}
Jugo De Moo
fuente
122

Muchas respuestas razonables ya. Voy a incluir una analogía que puede ayudar a algunos lectores. ::funciona muy parecido al separador de directorio del sistema de archivos ' /', cuando busca en su ruta un programa que le gustaría ejecutar. Considerar:

/path/to/executable

Esto es muy explícito: solo un ejecutable en esa ubicación exacta en el árbol del sistema de archivos puede coincidir con esta especificación, independientemente de la RUTA vigente. Similar...

::std::cout

... es igualmente explícito en el "árbol" del espacio de nombres C ++.

En contraste con tales rutas absolutas, puede configurar buenos shells UNIX (por ejemplo, zsh ) para resolver rutas relativas bajo su directorio actual o cualquier elemento en su PATHvariable de entorno, por lo que si PATH=/usr/bin:/usr/local/bin, y estuviera "en" /tmp, entonces ...

X11/xterm

... correría feliz /tmp/X11/xtermsi lo encontraran, de lo contrario /usr/bin/X11/xterm, de lo contrario /usr/local/bin/X11/xterm. Del mismo modo, digamos que estaba en un espacio de nombres llamado Xy tenía un " using namespace Y" en efecto, entonces ...

std::cout

... se puede encontrar en cualquiera de ::X::std::cout, ::std::cout, ::Y::std::cout, y posiblemente en otros lugares debido a las operaciones de búsqueda argumento dependiente (ADL, también conocido como búsqueda Koenig). Entonces, solo ::std::coutes realmente explícito sobre exactamente a qué objeto te refieres, pero afortunadamente nadie en su sano juicio crearía su propia clase / estructura o espacio de nombre llamado " std", ni nada llamado " cout", por lo que en la práctica usar solo std::coutestá bien.

Diferencias notables :

1) los shells tienden a usar la primera coincidencia usando el orden PATH, mientras que C ++ da un error de compilación cuando has sido ambiguo.

2) En C ++, los nombres sin ningún alcance inicial pueden coincidir en el espacio de nombres actual, mientras que la mayoría de los shells de UNIX solo lo hacen si se coloca .en el PATH.

3) C ++ siempre busca el espacio de nombres global (como tener /implícitamente su PATH).

Discusión general sobre espacios de nombres y explicidad de símbolos

El uso de ::abc::def::..."rutas" absolutas a veces puede ser útil para aislarlo de cualquier otro espacio de nombres que esté usando, parte de, pero realmente no tiene control sobre el contenido o incluso otras bibliotecas que el código del cliente de su biblioteca también usa. Por otro lado, también lo acopla más estrechamente a la ubicación "absoluta" existente del símbolo, y pierde las ventajas de la coincidencia implícita en los espacios de nombres: menos acoplamiento, movilidad más fácil del código entre espacios de nombres y código fuente más conciso y legible .

Como con muchas cosas, es un acto de equilibrio. Los C ++ estándar puts un montón de identificadores en virtud std::de que son menos "única" que cout, que los programadores pueden utilizar para algo completamente diferente en su código (por ejemplo merge, includes, fill, generate, exchange, queue, toupper, max). Dos bibliotecas no estándar no relacionadas tienen una probabilidad mucho mayor de usar los mismos identificadores que los autores generalmente no se conocen entre sí. Y las bibliotecas, incluida la biblioteca estándar de C ++, cambian sus símbolos con el tiempo. Todo esto potencialmente crea ambigüedad al volver a compilar el código antiguo, especialmente cuando ha habido un uso intensivo de using namespaces: lo peor que puede hacer en este espacio es permitirusing namespaces en encabezados para escapar de los ámbitos de los encabezados, de modo que una cantidad arbitrariamente grande de código de cliente directo e indirecto no puede tomar sus propias decisiones sobre qué espacios de nombres usar y cómo gestionar las ambigüedades.

Entonces, un líder ::es una herramienta en la caja de herramientas del programador C ++ para desambiguar activamente un choque conocido y / o eliminar la posibilidad de ambigüedad futura ...

Tony Delroy
fuente
8
+1 por buena analogía. las analogías no se utilizan lo suficiente como OMI como herramienta de enseñanza
Trevor Boyd Smith
38

::es el operador de resolución de alcance. Se usa para especificar el alcance de algo.

Por ejemplo, ::solo es el alcance global, fuera de todos los demás espacios de nombres.

some::thing se puede interpretar de cualquiera de las siguientes maneras:

  • somees un espacio de nombres (en el ámbito global, o un ámbito externo que el actual) y thinges un tipo , una función , un objeto o un espacio de nombres anidado ;
  • somees una clase disponible en el ámbito actual y thinges un objeto miembro , función o tipo de la someclase;
  • en una función miembro de la clase , somepuede ser un tipo base del tipo actual (o el tipo actual en sí) y thinges un miembro de esta clase, un tipo , función u objeto .

También puede tener un ámbito anidado, como en some::thing::bad. Aquí cada nombre puede ser un tipo, un objeto o un espacio de nombres. Además, el último bad, también podría ser una función. Los demás no pudieron, ya que las funciones no pueden exponer nada dentro de su alcance interno.

Entonces, volviendo a su ejemplo, ::thingsolo puede haber algo en el alcance global: un tipo, una función, un objeto o un espacio de nombres.

La forma en que lo usa sugiere (usado en una declaración de puntero) que es un tipo en el ámbito global.

Espero que esta respuesta sea completa y lo suficientemente correcta como para ayudarlo a comprender la resolución del alcance.

Klaim
fuente
2
@obounaim Considere este código liveworkspace.org/code/3Wabw0$5 class some { protected: int thing; }; class some_ext : public some { float thing; void action(){ some::thing = 42; thing = 666; } }; Aquí somehay una clase base de some_exty cuando escribe some::thingen funciones miembro de some_ext, significa el thingobjeto en el tipo base some. Sin some::, thingsolo significa el thingen el ámbito más cercano, es decir some_ext::thing. ¿Está más claro?
Klaim
17

:: se usa para vincular algo (una variable, una función, una clase, un typedef, etc.) a un espacio de nombres o a una clase.

si no hay un lado izquierdo antes ::, entonces subraya el hecho de que está utilizando el espacio de nombres global.

p.ej:

::doMyGlobalFunction();

Stephane Rolland
fuente
10

se llama operador de resolución de alcance. Se puede hacer referencia a un nombre global oculto utilizando el operador de resolución de alcance ::
Por ejemplo;

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

(Esta respuesta es principalmente para los googlers, porque OP ya ha resuelto su problema). El significado de antepuesto :: operador de resultado de alcance prefijado se ha descrito en otras respuestas, pero me gustaría agregar por qué la gente lo está usando.

El significado es "tomar nombre del espacio de nombres global, no otra cosa". Pero, ¿por qué esto debería deletrearse explícitamente?

Caso de uso: choque de espacio de nombres

Cuando tenga el mismo nombre en el espacio de nombres global y en el espacio de nombres local / anidado, se usará el local. Entonces, si desea el global, añádalo con ::. Este caso fue descrito en la respuesta de @Wyatt Anderson, por favor vea su ejemplo.

Caso de uso: enfatizar la función no miembro

Cuando escribe una función miembro (un método), las llamadas a otra función miembro y las llamadas a funciones que no son miembros (gratuitas) se parecen:

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

Pero puede suceder que Twistsea ​​una función miembro de clase hermana Ay que Bendsea ​​una función libre. Es decir, Twistpuede usar y modificar m_counery Bendno puede. Entonces, si desea asegurarse de que m_counterpermanezca 0, debe verificar Twist, pero no necesita verificarBend .

Entonces, para que esto se destaque más claramente, uno puede escribir this->Twistpara mostrarle al lector que Twistes una función miembro o escribir ::Bendpara mostrar que Bendes gratuito. O ambos. Esto es muy útil cuando está haciendo o planeando una refactorización.

Corcel
fuente
5

:: es un operador para definir el espacio de nombres.

Por ejemplo, si desea usar cout sin mencionar using namespace std;en su código, escriba esto:

std::cout << "test";

Cuando no se menciona ningún espacio de nombres, se dice que la clase pertenece al espacio de nombres global.

Vladimir Ivanov
fuente
1

"::" representa el operador de resolución de alcance. Las funciones / métodos que tienen el mismo nombre se pueden definir en dos clases diferentes. Para acceder a los métodos de un operador de resolución de alcance de clase particular se utiliza.

Vaman Acharya
fuente