Thread: Scope Resolution Operator Help?

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by shivam1992 View Post
    so its used to access static members from a class?
    The scope resolution operator is about more than accessing static members of a class.

    A namespace is a (named) scope. All names within the namespace belong in a scope with the same name as the namespace. Hence, to access something named x within a namespace named n, the syntax is n::x. Things that can be named include types, variables, and other scopes (so a namespace can be nested in a namespace,

    The name of a struct or class type in C++ is also a scope, with the same name as the struct type. Any member of a struct or class type can therefore be accessed using the syntax struct_name::member_name in any setting where access of that member makes sense.

    So, it is possible to use the scope resolution to access a static member of a class/struct
    Code:
    struct X
    {
        public:
           static int foo;
    };
    
    int X::foo;    // definition needed once and only once within a program
    
    int main()
    {
           X::foo = 42;    // changes the static member of X named foo.
    }
    Naturally, the assignment "X::foo = 42" above will not compile if foo is a private or protected member of X.

    However, scope resolution can also be used to access non-static members of a struct or class. For example;
    Code:
    #include <iostream>
    
    class Y
    {
        public:
    
              Y() {};
    
              virtual int Hello();
    };
    
    int Y::Hello()    // note use of scope operator to implement Y's Hello()
    {
        return 42;
    }
    
    class Z : public Y
    {
        public:
            Z() : Y() {};
    
            int Hello();
    
    };
    
    int Z::Hello()     //   Note use of scope operator in definition of Z's Hello()
    {
        return 2*Y::Hello();      //  Note use of scope operator to call Y's Hello()
    }
    
    int main()
    {
         Y *y = new Y;
         Y *z = new Z;
    
         std::cout << y->Hello() << '\n';
         std::cout << z->Hello() << '\n';
         std::cout << y->Y::Hello() << '\n';
         std::cout << z->Y::Hello() << '\n';     // note that this does not call Z::Hello()
    }
    I mention the last line for completeness - it is rarely a good idea in practice: if a caller needs to force the compiler to call Y::Hello() rather than Z::Hello() for an object of type Z, then that is usually a sign of a class design problem.

    There are limits to scope resolution. In the last code sample, for example, the line
    Code:
        std::cout << y->Z::Hello() << '\n';
    would not compile, since y is of type Y, and it does not make sense to call Z::Hello().


    Quote Originally Posted by shivam1992 View Post
    or when using isnt specified? , why would it be used if the using directive isnt present?
    This question shows you have got the idea of scope resolution completely backward. The scope resolution operator is not something that is used to avoid the "using" directive. The "using" directive is a flawed shortcut to reduce need to employ the scope resolution operator.

    Every name is within some scope. And the complete name of a variable, x, within a scope s is s::x. Given the syntax s::x, the compiler has only two choices: it accesses the name x within scope s, or it reports an error (eg because scope s does not exist, or because scope s does not contain anything named x). There is such a thing as an unnamed namespace, so
    Code:
    int x;
    
    int main()
    {
         x = 42;
    
         ::x = 50;    //  this affects the x above.   The only difference is that we tell the compiler specifically to change the value of x in the global (unnamed) namespace
    }
    What the using directive does is tell the compiler how to search for candidate matches to unadorned names (such as x). For example;
    Code:
    namespace Junk
    {
        int x;
    }
    
    using namespace Junk;
    
    int main()
    {
        x = 42;
    }
    The using directive tells the compiler that, if it sees a name, to look for a match in namespace Junk for a candidate match. There is no x in the global namespace (i.e. there is no ::x) so the assignment "x = 42" affects the variable Junk::x.

    If the using namespace directive is removed, this code will not compile because the compiler is no longer being told to look within namespace Junk. The compiler does not match "x" to "Junk::x", so the code will not compile (as the compiler cannot find anything to match ::x)

    Whether the using namespace directive is employed or not, however, this code will always be unambiguous.
    Code:
    namespace Junk
    {
        int x;
    }
    
    using namespace Junk;    // this line is optional
    
    int main()
    {
        Junk::x = 42;
    }
    Now, the next example, we come to the point of namespaces - three things named x, each with different meaning to the program, and all in different namespaces.
    Code:
    namespace Alpha
    {
        int x;
    }
    
    namespace Beta
    {
        int x;
    }
    using namespace Alpha;
    using namespace Beta;
    
    int x;    // within unnamed namespace
    
    int main()
    {
        x = 42;
    }
    This code will simply not compile. The reason is that the compiler has been told, when it is trying to resolve a name, to look in namespaces Alpha and Beta for candidate matches. Because of that, it finds Alpha::x, Beta::x, and ::x as candidates. The compiler has no reason to prefer one candidate over another, so will reject the code (typically with an error message about some form of ambiguity).

    If we absolutely must have namespaces Alpha and Beta visible to the compiler then, when compiling this code, there are few options. The first is to remove the "using namespace" directives. So, when it sees "x", the compiler will only consider ::x as a candidate.

    If we insist on employing the "using" directives, however, there is no alternative to using the scope resolution operator to resolve the ambiguity.
    Code:
    namespace Alpha
    {
        int x;
    }
    
    namespace Beta
    {
        int x;
    }
    using namespace Alpha;
    using namespace Beta;
    
    int x;    // within unnamed namespace
    
    int main()
    {
        ::x = 42;
    
         Alpha::x = 50;
         Beta::x = 60;
    
         x = 70;     // this line will still not compile unless the "using" directives are removed
    }
    This last sample demonstrates the problem of the "using" directive - once activated, its effects cannot be turned off. So, if ambiguity occurs due to a candidate matches for a name being in multiple namespaces, the ONLY solutions are to remove the offending "using" directives, or to use the scope resolution operator. This is why "using namespace" directives in header files is strongly discouraged - it imposes problems on the code which uses the header file.
    Last edited by grumpy; 02-22-2013 at 04:42 AM.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Scope resolution in C++
    By csonx_p in forum C++ Programming
    Replies: 6
    Last Post: 01-22-2009, 12:57 PM
  2. How to avoid typing std:: (scope resolution operator)
    By Sharan in forum C++ Programming
    Replies: 9
    Last Post: 04-30-2006, 08:25 PM
  3. quick question about scope resolution
    By *ClownPimp* in forum C++ Programming
    Replies: 8
    Last Post: 11-03-2002, 10:04 PM
  4. scope resolution operator ::: ??
    By Carlos in forum Windows Programming
    Replies: 7
    Last Post: 10-01-2002, 08:56 PM
  5. Replies: 4
    Last Post: 06-04-2002, 06:09 AM