2010-09-06 12 views
8

Un compañero de trabajo, escribe habitualmente algo como esto:¿Qué significa si una llamada a método comienza con dos dos puntos?

::someObject->someMethod(anAttribute, anotherAttribute); 

someObject es una variable global.
Esos dos puntos me parecen extraños. El código se compila y funciona perfectamente sin ellos.

El compañero de trabajo afirma que esos dos puntos hacen someObject explícitamente global y así evitar la confusión con un posible local someObject. ¿Pensaría que no sería capaz de definir someObject localmente si ya estaba definido globalmente?

¿Podría arrojar algo de luz sobre lo que significan esos dos puntos y si son necesarios?

+5

Siempre destacaría los vars globals. Incluso si los vars locales con el mismo nombre fueron prohibidos. B/c globales son ** Evil ** –

+0

El uso de '::' no está limitado a variables globales; se refiere a algo global. Por lo tanto, si tiene una clase legacy 'string', es recomendable referirse a ella como' :: string' y así evitar confusiones con 'std :: string'. – MSalters

+0

@MSalters: b.t.w. ¿Qué pasa si escribo 'using namespace std' y luego' :: string str'? ¿Cuál será el tipo de 'str'? –

Respuesta

8

Su compañero de trabajo tiene razón. De hecho puede definir un local de someObject que ocultar la someObject mundial dentro de ese ámbito:

SomeClass* someObject = ...; 

// here the global object is visible 
someObject->someMethod(anAttribute, anotherAttribute); // calls the global object 

void someMethod() { 
    SomeClass* someObject = ...; 
    // here the local object hides the global 
    ::someObject->someMethod(anAttribute, anotherAttribute); // calls the global object 
    someObject->someMethod(anAttribute, anotherAttribute); // calls the local object 
} 

// here again only the global object is visible 
someObject->someMethod(anAttribute, anotherAttribute); // calls the global object 

Scopes puede ser embebido dentro de otros ámbitos de forma recursiva, por tanto, es posible que tenga un espacio de nombres dentro del ámbito mundial, una clase dentro de un espacio de nombres, una clase interna dentro de la clase, un método dentro de una clase interna, un bloque dentro del método ... etc. Y puede tener variables/clases/métodos/... de nombres idénticos en cualquiera de estos ámbitos. Entonces, identificar a qué entidad se refiere un nombre específico no es una tarea trivial en C++. Se conoce como name lookup.

En resumen, cada vez que el compilador encuentra un nombre, busca ese nombre a partir del ámbito más interno. Es decir. dentro de someMethod, el nombre someObject se corresponde con el objeto definido localmente. ::someObject anula este comportamiento predeterminado y hace que la búsqueda del compilador solo se encuentre dentro del alcance más externo (global), por lo que encuentra el objeto global en lugar del local.

3

El compañero de trabajo afirma que esos dos puntos hacen someObject explícitamente global y por lo tanto evitar la confusión con un posible someObject local.

Sí - significa que la función puede ser, y solo debe ser, coincidente en el espacio de nombres global. Hace obvio que está tratando con un global, y evitaría la coincidencia accidental con algo más local (función local de beit, miembro de objeto, miembro de espacio de nombres, en un espacio de nombres que está usando, una coincidencia de búsqueda de Koenig, etc.).

Me gustaría pensar que usted no sería capaz de definir someObject localmente si ya estaba definido a nivel mundial?

Sería una mala idea hacerlo un error. Digamos que un equipo de programadores decide que quiere agregar una variable llamada "last_error" a su espacio de nombres: no deberían tener que preocuparse si las funciones existentes en el espacio de nombres usan el mismo nombre para una variable local. Si copia una función de un espacio de nombres o clase a otro, no debería tener que realizar sustituciones de identificadores propensas a errores en la implementación.

En cuanto a los beneficios de la ::, considere:

namespace X 
{ 
    void fn() { 
     rip(data, bytes); // MP3 rip this data 
    } 
} 

... entonces fn() necesita ser movido rápidamente en espacio de nombres ... Y

namespace Y 
{ 
    void rip(const char* message, int exit_code); /* for fatal errors */ 
    ... 
} 

... contra copias ocasionales pegar en las entrañas de Y podría pasar fácilmente por alto que el registro no coincidirá con la misma función global que cuando fn estaba en el espacio de nombres X, pero, como se ilustra, la funcionalidad puede variar notablemente :-).

Puede pensar en cada espacio de nombre, clase/estructura y funciones formando un árbol, donde cada nivel debe tener una clave única (es decir, no hay clases del mismo nombre), pero las decendencias siempre son independientes entre sí y su antepasados. El aumento de la libertad para variar de forma independiente es esencial para permitir que muchas personas trabajen simultáneamente en un gran problema.

Podría arrojar alguna luz sobre lo que esos dos puntos significan y si son necesarios ?

En este uso específico, :: :: probablemente no sea estrictamente necesario. Agrega un poco de protección, pero hace que sea más difícil mover la variable a un alcance más local más tarde, aunque eso no es tan importante porque el compilador le informará sobre los lugares que continúan refiriéndose a :: x después de mover x.

4

Definitivamente puede definir algún Objeto localmente aunque haya uno global. Las dos variables tienen un alcance diferente, por lo que el compilador sabe que hay una diferencia entre los dos, y los dos puntos dobles le permiten referirse al global.

Esto también se aplica a las clases fuera de un espacio de nombres; es decir, para referirse a una clase Foo de la clase Bar :: Foo, utiliza :: Foo para decirle al compilador que está hablando sobre el que no está en un espacio de nombres.

He aquí un ejemplo que muestra que funcione:

#include<stdio.h> 

int someInt = 4; 

int main() { 
     int someInt = 5; 
     printf("%d", someInt+::someInt); 
     return 0; 
} 

Si compilar y ejecutar ese trozo de código, éste salida 9.

1

Sólo un menor añadir a todos los demás puntos agradables que tienen ven en la respuesta.

Básicamente :: invoca la búsqueda de nombres calificados en el espacio de nombres global. Sin embargo, no se garantiza que esté libre de problemas, especialmente frente a las directivas de uso indiscriminado.

El código que se muestra ilustra una propiedad importante de la búsqueda de nombres calificados. El punto aquí es que se buscan los espacios de nombres nominados mediante el uso de directivas en el namspace global. Sin embargo, se omiten las directivas en espacios de nombres que tienen el nombre que se busca.

namespace Z{ 
     void f(){cout << 1;} 
    } 

    namespace Y{ 
     void f(){cout << 2;} 
     using namespace Y;  // This namespace is not searched since 'f' is found in 'Y' 
    } 

#if 0 
    namespace Z{ 
     void f(){cout << 3;} 
     using namespace Y;  // This namespace is not searched since 'f' is found in 'Y' 
    } 
    using namespace Z; 
#endif 
    using namespace Y; 

    int main(){ 
     ::f();     // Prints 2. There is no ambiguity 
    } 

En el código que se muestra, si las líneas con la directiva #if están habilitados, hay una ambigüedad en la resolución del nombre de 'f'.

Cuestiones relacionadas