views:

161

answers:

4

A coworker routinely writes something like this:

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

someObject is a global variable.
Those two colons seem strange to me. The code compiles and runs just fine without them.

The coworker claims that those colons make someObject explicitly global and thus prevent confusion with a possible local someObject. I would think that you would not be able to define someObject locally if it was already defined globally?

Could you shed some light on what those colons mean and whether they are necessary?

+3  A: 

The coworker claims that those colons make someObject explicitly global and thus prevent confusion with a possible local someObject.

Yes - it means the function can be, and must only be, matched in the global namespace. It makes it obvious you're dealing with a global, and would prevent accidental matching against something more local (beit function local, an object member, namespace member, in a namespace you're using, a Koenig lookup match etc.).

I would think that you would not be able to define someObject locally if it was already defined globally?

It would be a very bad idea to make it an error. Say a team of programmers decides they want to add a variable called "last_error" to their namespace: they shouldn't have to worry if existing functions in the namespace use the same name for a local variable. If you copy a function from one namespace or class to another, you shouldn't have to make error-prone identifier substitutions in the implementation.

Regarding the benefits of ::, consider:

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

...then fn() needs to be moved quickly into namespace Y...

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

...a casual copy-paste into the guts of Y could easily overlook that log won't match the same global function it used to when fn was in namespace X, but - as illustrated - the functionality may differ markedly :-).

You can think of each namespace, class/struct and functions forming a tree, where each level must be uniquely keyed (i.e. no same-named classes in the same namespace), but decendents are always independent of each other and their ancestors. Increasing freedom to vary independently is essential for letting many people work simultaneously on a big problem.

Could you shed some light on what those colons mean and whether they are necessary?

In this specific usage, the :: probably isn't strictly necessary. It adds a little protection, but makes it harder to move the variable to a more local scope later - though that's not so important because the compiler will tell you about the places that continue to refer to ::x after x is moved.

Tony
+5  A: 

Your coworker is right. You can indeed define a local someObject which would hide the global someObject within that scope:

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 can be embedded within other scopes recursively, thus you may have a namespace within global scope, a class within a namespace, an inner class within the class, a method within an inner class, a block within the method... etc. And you may have variables/classes/methods/... of identical names in any of these scopes. So identifying what entity a specific name is referring to is not a trivial task in C++. It is known as name lookup.

In brief, whenever the compiler finds a name, it looks up that name starting from the innermost scope. I.e. inside someMethod, the name someObject is matched by the object defined locally. ::someObject overrides this default behaviour and makes the compiler search only within the outermost (global) scope, thus it finds the global object instead ofthe local.

Péter Török
+3  A: 

You can indeed define a someObject locally even though there is a global one. The two variables have different scope, so the compiler knows there's a difference between the two, and the double colons let you refer to the global one.

This also applies to classes outside of a namespace; i.e., to refer to a class Foo from the class Bar::Foo, you use ::Foo to tell the compiler you are talking about the one that isn't in a namespace.

Here's an example that shows it working:

#include<stdio.h>

int someInt = 4;

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

If you compile and run that piece of code, it will output 9.

Michael Madsen
+1  A: 

Just a minor add on to all other nice points which have come in the response.

Basically :: invokes qualified name lookup in the global namespace. However it is not guaranteed to be problem free especially in the face of indiscriminate using directives.

The code shown illustrates an important property of qualified name lookup. The point here is that namespaces nominated by using directives in the global namspace are searched. However using directives in namespaces that have the name being searched are skipped.

    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
    }

In the code shown, if lines with the #if directive are enabled, there is an ambiguity in resolving the name 'f'.

Chubsdad