Topic: Curious nested class visibility


Author: gi2nospam@mariani.ws (Gianni Mariani)
Date: Fri, 2 Dec 2005 06:04:56 GMT
Raw View
Somone (Mr Dyl) recently posted the predecessor to the code example
below on comp.lang.c++.

What makes me curious is why does the standard not allow Nested_B
visibility into A ?  It seems strange that I can find the address of a
member of A but I can't reference a member directly.


class A {
public:
    class Nested_A {
    protected:
       A* ptrA;
    };
    protected:
       int X;
};

class B : public A {
public:
    class Nested_B : public Nested_A {
       int foo() {return(ptrA->X);}
       // error: "A::X" is not accessible through a "A*"
       int foo1() {return(ptrA->*(&B::X));} // &B::X == &A::X
    };
};

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: squell@alumina.nl (Marc Schoolderman)
Date: Sat, 3 Dec 2005 01:34:25 GMT
Raw View
Gianni Mariani wrote:

> What makes me curious is why does the standard not allow Nested_B
> visibility into A ?  It seems strange that I can find the address of a
> member of A but I can't reference a member directly.

> class B : public A {
> public:
>    class Nested_B : public Nested_A {
>       int foo() {return(ptrA->X);}
>       // error: "A::X" is not accessible through a "A*"
>       int foo1() {return(ptrA->*(&B::X));} // &B::X == &A::X
>    };
> };

This is because a nested class does not (in C++98) automatically gain
access to the surrounding class's non-public members unless explicitly
declared a friend:

class foo {
     int x;
     struct inner {
         inner(foo* p) { p->x = 4; }     // cannot access foo::x
     };
};

GCC doesn't reject foo1(), but it is wrong (afaik). In any case, this
has been recognised as a defect, so it will probably go away in a future
standard, see

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45

~Marc.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "vish" <vishakha@gmail.com>
Date: Fri, 2 Dec 2005 19:34:00 CST
Raw View
Nested_B will have ptrA as protected member. ptrA is an object of class
A and X is a protected member of A, an object cannot access protected
member directly.

-Vish

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: johnchx2@yahoo.com
Date: Sat, 3 Dec 2005 16:16:15 CST
Raw View
Gianni Mariani wrote:

> What makes me curious is why does the standard not allow Nested_B
> visibility into A ?  It seems strange that I can find the address of a
> member of A but I can't reference a member directly.

This is a manifestion of an open issue, which basically boils down to
"the expression '&Derived::mem' may not have the type you think it
has."  If mem has type T and is inherited from Base, &Derived::mem has
the type pointer-to-member-of-Base-of-type-T.  (5.3.1/2)

http://www2.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#203

I don't think anyone has previously pointed out that this issue
constitutes an access control loophole.

Let me give a simpler example of the same effect:

class A {
   protected:
      int i;
};

class B: public A {
   public:
      void bar( A& a )
      {
         int A::* pma  = &B::i;
         int A::* pma2 = &A::i;  // error: access violation
         int B::* pmb  = &B::i;
         a.*pma  = 5;
         a.*pma2 = 5;
         a.*pmb  = 5;            // error: incompatible type
      }
};

The first error (access control violation) is what we'd expect:  we
can't refer to protected members of A, only to protected members of A
sub-objects of B.  The second error (incompatible type) shows that we
can't apply a pointer-to-member-of-B to an object of type A.  So far,
so good.

However, the initialization of pma shows that we can create an object
of type pointer-to-member-of-A by naming a member of B.  Since access
control applies only to the use of names, this creates a loophole:  we
can access a member of one class by naming a member of another.

Personally, I think this raises the importance of issue 203.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]