5

This code does not work (MS VS 2005),

b->funcA();
B::iterator iter;

cant access protected members declared in class A.

If I remove class D, everything compiles nicely.

I wonder if it's just a bug or standard?

class A
{
protected:
    void funcA() {  }
    class iterator {    };
};

class D {
    class B : public A {
        class C {
            B* b;
        public:
            void funcC() {
                b->funcA();
                B::iterator iter;
            }
        };
    public:
        void funcB() {
            funcA();
        }
    };
};

Thanks!

Wim Coenen
  • 66,094
  • 13
  • 157
  • 251
Leo
  • 131
  • 1
  • 9

3 Answers3

3

The current C++ standard (C++03) has the following restriction that would make your code ill-formed:

The members of a nested class have no special access to members of an enclosing class, nor to classes or functions that have granted friendship to an enclosing class; the usual access rules shall be obeyed (C++03 11.8/1).

However, this rule has been reversed in the forthcoming C++ standard (C++0x). The paragraph now reads:

A nested class is a member and as such has the same access rights as any other member. The members of an enclosing class have no special access to members of a nested class; the usual access rules shall be obeyed (C++0x Draft N3225 11.8/1).

So, under the old interpretation, your code is incorrect but under the new interpretation it is correct. This is basically a defect in the original C++ Standard; the defect was noted in 1998 and the correction was agreed to in 2001. You can find details on that in CWG Defect 45.


Note that regardless which interpretation you want to use, I think there is still a bug in the compiler. The following is the minimal repro, and generates the same error when using Visual C++ 2010:

class A {
protected:
    void f() { }
};

struct D {
    struct B : A {
        struct C {
            void g() { 
                B().f(); 
            }
        };
    };
};

However, if you remove D and put B in the global namespace, the compiler accepts the code.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • Are you filing the bug report on MS Connect or shall I? In either case, a link should be placed here so the SO community can upvote it. – Ben Voigt Feb 17 '11 at 16:42
  • @Ben: I was going to report it internally, but if you'd like to report it on Connect, that would be good; it would give the issue external visibility and allow the OP to track the issue. – James McNellis Feb 17 '11 at 16:58
  • Oh... I never realized you were a 'softie. With an MVP and devdiv member both reporting this, it ought to get some action. [Bug #644861](https://connect.microsoft.com/VisualStudio/feedback/details/644861/member-access-from-nested-classes-is-affected-by-nesting-depth) – Ben Voigt Feb 17 '11 at 17:09
  • @Leo: And... we have [an official answer](http://connect.microsoft.com/VisualStudio/feedback/details/644861/member-access-from-nested-classes-is-affected-by-nesting-depth). Basically, this part of C++0x wasn't ready in VC++ 2010, the compiler team provided a workaround, and we should expect the next VC++ to handle it properly. – Ben Voigt Mar 01 '11 at 03:38
  • @Ben: Thanks for following up. That's not quite what Ulzii said, though :-) The C++0x behavior will be implemented in some future release, not necessarily the next release (I hope that all the remaining C++0x features are implemented in the next version, but I'm not holding my breath :-D). Also, I didn't see your previous comment, but yes, I joined Microsoft in September. – James McNellis Mar 01 '11 at 06:53
0

The fact that C is nested in B doesn't give C special access to B's members.

Solutions for funcA(): (1) Make funcA() public. or (2) Call funcB() instead (delegating to funcA()).

Solution for iterator: Make iterator public.

Martin Stone
  • 12,682
  • 2
  • 39
  • 53
  • What version of the standard are you reading? Section `[class.access.nest]` of draft n3225 says the opposite. – Ben Voigt Feb 17 '11 at 16:28
  • @Ben Voight: "INTERNATIONAL ISO/IEC STANDARD 14882 First edition 1998-09-01", since you ask, but I couldn't find it until I saw the answer from Nawaz. Are you getting confused with Java? – Martin Stone Feb 17 '11 at 16:34
  • @Ben Voight: He says he's using VC2005. Not sure that supports C++0x. – Martin Stone Feb 17 '11 at 16:36
  • @Martin: No, I'm using a much more recent version of the C++ spec (which is still in the final stages of standardization). And I know VC2005 doesn't support C++0x. That's why I asked what standard you were referring to instead of just applying a downvote because my copy said otherwise. – Ben Voigt Feb 17 '11 at 16:36
  • @Ben: Understood. I think I need to get a new copy -- My compiler (VS2008) likewise can't make its mind up. (Error goes away when not nested in D.) – Martin Stone Feb 17 '11 at 16:45
  • Well, in VS2005 error goes away too if I remove D class. One more interesting feature (bug): if I derive D from A, C can access iterator but can't access function from class A :o – Leo Feb 17 '11 at 17:15
0

C is nested class of B. Nested class cannot access private and protected members of enclosing class. That is why the code doesn't compile, and correctly gives compilation error.

The C++ Standard (2003) says in $11.8/1 [class.access.nest],

The members of a nested class have no special access to members of an enclosing class, nor to classes or functions that have granted friendship to an enclosing class; the usual access rules (clause 11) shall be obeyed. The members of an enclosing class have no special access to members of a nested class; the usual access rules (clause 11) shall be obeyed.

Example from the Standard itself:

class E 
{
    int x;
    class B { };
    class I 
    {
        B b; // error: E::B is private
        int y;
        void f(E* p, int i)
        {
           p->x = i; // error: E::x is private
        }
   };
   int g(I* p)
   {
       return p->y; // error: I::y is private
   }
};

So according to it, presence or absence of D should not effect anything. It should give compilation error, even if D is absent.

Similar topic was created yesterday: Are inner classes in C++ automatically friends?


By the way, it's a defect in C++03 which has been corrected in C++0x.

This is allowed in C++0x. See this Access to nested classes

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 1
    But this reverses in C++0x. `I` has access to private members of `E` (`E` still has no special access to members of `I`). Furthermore, the question says the result depends on the presence of `class D`... which should have no effect under either C++03 or C++0x. – Ben Voigt Feb 17 '11 at 16:32