Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #6574 > unrolled thread

Does friendship extend to inner classes?

Started byJuha Nieminen <nospam@thanks.invalid>
First post2011-06-10 18:09 +0000
Last post2011-06-13 18:46 +0200
Articles 11 — 7 participants

Back to article view | Back to comp.lang.c++


Contents

  Does friendship extend to inner classes? Juha Nieminen <nospam@thanks.invalid> - 2011-06-10 18:09 +0000
    Re: Does friendship extend to inner classes? Saeed Amrollahi <amrollahi.saeed@gmail.com> - 2011-06-10 13:04 -0700
      Re: Does friendship extend to inner classes? Juha Nieminen <nospam@thanks.invalid> - 2011-06-11 04:45 +0000
        Re: Does friendship extend to inner classes? Geoff <geoff@invalid.invalid> - 2011-06-12 10:53 -0700
    Re: Does friendship extend to inner classes? Ruben Safir <mrbrklyn@panix.com> - 2011-06-11 20:41 +0000
      Re: Does friendship extend to inner classes? Juha Nieminen <nospam@thanks.invalid> - 2011-06-12 14:10 +0000
      Re: Does friendship extend to inner classes? Werner <werasm@gmail.com> - 2011-06-13 03:51 -0700
    Re: Does friendship extend to inner classes? Kai-Uwe Bux <jkherciueh@gmx.net> - 2011-06-12 23:01 +0200
      Re: Does friendship extend to inner classes? "Alf P. Steinbach /Usenet" <alf.p.steinbach+usenet@gmail.com> - 2011-06-12 23:31 +0200
      Re: Does friendship extend to inner classes? Juha Nieminen <nospam@thanks.invalid> - 2011-06-13 12:20 +0000
        Re: Does friendship extend to inner classes? Kai-Uwe Bux <jkherciueh@gmx.net> - 2011-06-13 18:46 +0200

#6574 — Does friendship extend to inner classes?

FromJuha Nieminen <nospam@thanks.invalid>
Date2011-06-10 18:09 +0000
SubjectDoes friendship extend to inner classes?
Message-ID<4df25dc2$0$2869$7b1e8fa0@news.nbl.fi>
  Consider the following:

//-----------------------------------------------
class A
{
    class B
    {
        int i;
        friend class A;
    };

    class C
    {
        void foo(B&);
    };
};

void A::C::foo(B& b)
{
    b.i = 5; // Allowed or not?
}
//-----------------------------------------------

  It seems that gcc and Visual Studio disagree on this (gcc allows it,
Visual Studio issues an error). Which one is right?

[toc] | [next] | [standalone]


#6579

FromSaeed Amrollahi <amrollahi.saeed@gmail.com>
Date2011-06-10 13:04 -0700
Message-ID<a1be13e2-b9c0-4578-9353-243931d17746@x3g2000yqj.googlegroups.com>
In reply to#6574
On Jun 10, 10:09 pm, Juha Nieminen <nos...@thanks.invalid> wrote:
>   Consider the following:
>
> //-----------------------------------------------
> class A
> {
>     class B
>     {
>         int i;
>         friend class A;
>     };
>
>     class C
>     {
>         void foo(B&);
>     };
>
> };
>
> void A::C::foo(B& b)
> {
>     b.i = 5; // Allowed or not?}
>
> //-----------------------------------------------
>
>   It seems that gcc and Visual Studio disagree on this (gcc allows it,
> Visual Studio issues an error). Which one is right?

Hi
I tested and ran you code under GCC 4.6.0 and Visual Studio 2008.
Both allowed!
Actually, I wrapped your code to the following program:

#include <iostream>
class A
{
 class B {
   int i;
   friend class A;
 } b;

 class C {
 public:
   void foo(B&);
 } c;
public:
  A() { c.foo(b); }
};

void A::C::foo(B& b)
{
  b.i = 5; // Allowed or not?
  std::cout << "It's allowed ...\n";
}

int main()
{
  A a;
  return 0;
}

The output is: "It's allowed ...
But, I surprised, because I found nothing in
Draft International Standard about such grants.
Indeed I found the following wording in FIDS: n2390:
section 9.7 paragraph 4:
  Like a member function, a friend function (11.3) defined within
  a nested class is in the lexical scope of that class; it obeys
  the same rules for name binding as a static member function of
  that class (9.4), but it has no special access rights to members
  of an enclosing class.

HTH,
  -- Saeed Amrollahi

[toc] | [prev] | [next] | [standalone]


#6605

FromJuha Nieminen <nospam@thanks.invalid>
Date2011-06-11 04:45 +0000
Message-ID<4df2f2f7$0$2842$7b1e8fa0@news.nbl.fi>
In reply to#6579
Saeed Amrollahi <amrollahi.saeed@gmail.com> wrote:
> I tested and ran you code under GCC 4.6.0 and Visual Studio 2008.
> Both allowed!

  I should have specified that when I tried it (well, something similar)
with VS 2005, it gave an error about the private variable being 
inaccessible.

[toc] | [prev] | [next] | [standalone]


#6659

FromGeoff <geoff@invalid.invalid>
Date2011-06-12 10:53 -0700
Message-ID<q8v9v69rn7ddp0okjqj7ib9u1l9iq9e56g@4ax.com>
In reply to#6605
On 11 Jun 2011 04:45:43 GMT, Juha Nieminen <nospam@thanks.invalid>
wrote:

>Saeed Amrollahi <amrollahi.saeed@gmail.com> wrote:
>> I tested and ran you code under GCC 4.6.0 and Visual Studio 2008.
>> Both allowed!
>
>  I should have specified that when I tried it (well, something similar)
>with VS 2005, it gave an error about the private variable being 
>inaccessible.

It's allowed in VS2010. 

[toc] | [prev] | [next] | [standalone]


#6628

FromRuben Safir <mrbrklyn@panix.com>
Date2011-06-11 20:41 +0000
Message-ID<it0jtc$j0s$1@reader1.panix.com>
In reply to#6574
Juha Nieminen <nospam@thanks.invalid> wrote:
>  Consider the following:
> 
> //-----------------------------------------------
> class A
> {
>    class B
>    {
>        int i;
>        friend class A;
>    };
> 
>    class C
>    {
>        void foo(B&);
>    };
> };
> 
> void A::C::foo(B& b)
> {
>    b.i = 5; // Allowed or not?
> }
> //-----------------------------------------------
> 
>  It seems that gcc and Visual Studio disagree on this (gcc allows it,
> Visual Studio issues an error). Which one is right?


This code is useless since there is no public or private declarations,
no main and theorectically, friend is irrelavent to the example.


[toc] | [prev] | [next] | [standalone]


#6654

FromJuha Nieminen <nospam@thanks.invalid>
Date2011-06-12 14:10 +0000
Message-ID<4df4c8c5$0$2815$7b1e8fa0@news.nbl.fi>
In reply to#6628
Ruben Safir <mrbrklyn@panix.com> wrote:
> This code is useless since there is no public or private declarations,
> no main and theorectically, friend is irrelavent to the example.

  Thanks for your completely useless answer.

  So what if there are no public or private declarations? Any member
declaration is by default private, so the 'private:' keyword would be
completely unnecessary. Compilation units do not need a 'main' function.
The 'friend' declaration is absolutely relevant to the question because
the question was: Should the given example code compile or not? (With
gcc it compiles, with VS2005 it doesn't.)

[toc] | [prev] | [next] | [standalone]


#6689

FromWerner <werasm@gmail.com>
Date2011-06-13 03:51 -0700
Message-ID<bca48a3c-1d95-41b1-88d3-d369e923c8c7@v18g2000yqe.googlegroups.com>
In reply to#6628
On Jun 11, 10:41 pm, Ruben Safir <mrbrk...@panix.com> wrote:

> This code is useless since there is no public or private declarations,
> no main and theorectically, friend is irrelavent to the example.

Not...

This merely implies everything is private (the difference between
keyword "class" and "struct"?). There needn't be a main
function to compile a file. Hence the code is perfectly
fine, in fact - I just compiled it at

http://www.comeaucomputing.com/tryitout/.

According to comeau, friendship is required for it to
compile.

Kind regards,

Werner

[toc] | [prev] | [next] | [standalone]


#6661

FromKai-Uwe Bux <jkherciueh@gmx.net>
Date2011-06-12 23:01 +0200
Message-ID<it39ra$m54$1@hoshi.visyn.net>
In reply to#6574
Juha Nieminen wrote:

>   Consider the following:
> 
> //-----------------------------------------------
> class A
> {
>     class B
>     {
>         int i;
>         friend class A;
>     };
> 
>     class C
>     {
>         void foo(B&);
>     };
> };
> 
> void A::C::foo(B& b)
> {
>     b.i = 5; // Allowed or not?
> }
> //-----------------------------------------------
> 
>   It seems that gcc and Visual Studio disagree on this (gcc allows it,
> Visual Studio issues an error). Which one is right?

The C++03 standard [11.4/2]:

  Declaring a class to be a friend implies that the names of private and 
  protected members from the class granting friendship can be accessed in   
  declarations of members of the befriended class. [Note: this means that 
  access to private and protected names is also granted to member functions 
  of the friend class (as if the functions were each friends) and to the 
  static data member definitions of the friend class. This also means that 
  private and protected type names from the class granting friendship can be 
  used in the base-clause of a nested class of the friend class. 

and now for the important sentence:

  However, the declarations of members of classes nested within the friend 
  class cannot access the names of private and protected members from the 
  class granting friendship. 

There is also an example:

  Also, because the base-clause of the friend class is not part of its 
  member declarations, the base-clause of the friend class cannot access the 
  names of the private and protected members from the class granting 
  friendship. For example,
      class A {
                 class B { };
                 friend class X;
      };
      class X : A::B {        // ill-formed: A::B cannot be accessed
                              // in the base-clause for X
                 A::B mx;     // OK: A::B used to declare member of X
                 class Y : A::B {  // OK: A::B used to declare member of X
                      A::B my;  // ill-formed: A::B cannot be accessed
                                // to declare members of nested class of X
                 };
      };
  ]
  ...


This explanation in in a non-normative a note; and one could argue that the 
interpretation that friendship does not extend to inner classes is a little 
bit streched given the wording of the normative provision. C++0X has taken 
that stance. In n3291, the corresponding clause [11.3/2] reads:

  Declaring a class to be a friend implies that the names of private and 
  protected members from the class granting friendship can be accessed in 
  the base-specifiers and member declarations of the befriended class.
  [ Example:
   class A {
     class B { };
     friend class X;
   };
   struct X : A::B {    // OK: A::B accessible to friend
     A::B mx;           // OK: A::B accessible to member of friend
     class Y {
        A::B my;        // OK: A::B accessible to nested member of friend
     };
   };
   -- end example ]
   ...

As one can see from the example, C++ is changing in this regard. That could 
explain your observation that compilers disagree on this one.


Best,

Kai-Uwe Bux

[toc] | [prev] | [next] | [standalone]


#6662

From"Alf P. Steinbach /Usenet" <alf.p.steinbach+usenet@gmail.com>
Date2011-06-12 23:31 +0200
Message-ID<it3b32$fqu$1@dont-email.me>
In reply to#6661
* Kai-Uwe Bux, on 12.06.2011 23:01:
> Juha Nieminen wrote:
>
>>    Consider the following:
>>
>> //-----------------------------------------------
>> class A
>> {
>>      class B
>>      {
>>          int i;
>>          friend class A;
>>      };
>>
>>      class C
>>      {
>>          void foo(B&);
>>      };
>> };
>>
>> void A::C::foo(B&  b)
>> {
>>      b.i = 5; // Allowed or not?
>> }
>> //-----------------------------------------------
>>
>>    It seems that gcc and Visual Studio disagree on this (gcc allows it,
>> Visual Studio issues an error). Which one is right?
>
> The C++03 standard [11.4/2]:
>
>    Declaring a class to be a friend implies that the names of private and
>    protected members from the class granting friendship can be accessed in
>    declarations of members of the befriended class. [Note: this means that
>    access to private and protected names is also granted to member functions
>    of the friend class (as if the functions were each friends) and to the
>    static data member definitions of the friend class. This also means that
>    private and protected type names from the class granting friendship can be
>    used in the base-clause of a nested class of the friend class.
>
> and now for the important sentence:
>
>    However, the declarations of members of classes nested within the friend
>    class cannot access the names of private and protected members from the
>    class granting friendship.
>
> There is also an example:
>
>    Also, because the base-clause of the friend class is not part of its
>    member declarations, the base-clause of the friend class cannot access the
>    names of the private and protected members from the class granting
>    friendship. For example,
>        class A {
>                   class B { };
>                   friend class X;
>        };
>        class X : A::B {        // ill-formed: A::B cannot be accessed
>                                // in the base-clause for X
>                   A::B mx;     // OK: A::B used to declare member of X
>                   class Y : A::B {  // OK: A::B used to declare member of X
>                        A::B my;  // ill-formed: A::B cannot be accessed
>                                  // to declare members of nested class of X
>                   };
>        };
>    ]
>    ...
>
>
> This explanation in in a non-normative a note; and one could argue that the
> interpretation that friendship does not extend to inner classes is a little
> bit streched given the wording of the normative provision. C++0X has taken
> that stance. In n3291, the corresponding clause [11.3/2] reads:
>
>    Declaring a class to be a friend implies that the names of private and
>    protected members from the class granting friendship can be accessed in
>    the base-specifiers and member declarations of the befriended class.
>    [ Example:
>     class A {
>       class B { };
>       friend class X;
>     };
>     struct X : A::B {    // OK: A::B accessible to friend
>       A::B mx;           // OK: A::B accessible to member of friend
>       class Y {
>          A::B my;        // OK: A::B accessible to nested member of friend
>       };
>     };
>     -- end example ]
>     ...
>
> As one can see from the example, C++ is changing in this regard. That could
> explain your observation that compilers disagree on this one.

I feel dizzy with all these to me arbitrary changes.

I remember, at meeting of Oslo C++ User Group some years ago the lecturer raised 
a question about visibility for nested class friend thing.

And it turned out the rules had changed already two or three times  --  then.

So I think this is a very practical question:

HOW TO DEAL WITH THE EVER CHANGING RULES?

It is like shooting at a moving target.

And since that is a classical problem, someone must (hopefully) found a solution?


Cheers,

- Alf

-- 
blog at <url: http://alfps.wordpress.com>

[toc] | [prev] | [next] | [standalone]


#6691

FromJuha Nieminen <nospam@thanks.invalid>
Date2011-06-13 12:20 +0000
Message-ID<4df60094$0$2839$7b1e8fa0@news.nbl.fi>
In reply to#6661
Kai-Uwe Bux <jkherciueh@gmx.net> wrote:
> As one can see from the example, C++ is changing in this regard. That could 
> explain your observation that compilers disagree on this one.

  I suppose this means that, technically speaking, gcc (and apparently
newer versions of Visual Studio) are breaking the standard when they are
compiling in C++98/03 compatibility mode (ie. with no C++1x extensions
enabled)?

  I suppose it also means that if you want to make your program 
C++98-compliant, you will have to avoid using friendship like this 
(something which can be broken accidentally because the compiler doesn't 
protect you from the error).

  Yes, this happened to me in a real project, and I was wondering which 
one was being incorrect, gcc or VS2005. From what has been discussed it 
seem that the latter is, technically speaking, acting properly.

[toc] | [prev] | [next] | [standalone]


#6705

FromKai-Uwe Bux <jkherciueh@gmx.net>
Date2011-06-13 18:46 +0200
Message-ID<it5f3n$911$1@hoshi.visyn.net>
In reply to#6691
Juha Nieminen wrote:

> Kai-Uwe Bux <jkherciueh@gmx.net> wrote:
>> As one can see from the example, C++ is changing in this regard. That
>> could explain your observation that compilers disagree on this one.
> 
>   I suppose this means that, technically speaking, gcc (and apparently
> newer versions of Visual Studio) are breaking the standard when they are
> compiling in C++98/03 compatibility mode (ie. with no C++1x extensions
> enabled)?
[...]

I am not sure whether the situation is all that clear cut.

You snipped the quotes from the standard and the draft. Let me re-quote the 
normative parts:

Standard [11.4/2]:

  Declaring a class to be a friend implies that the names of private and 
  protected members from the class granting friendship can be accessed in   
  declarations of members of the befriended class. [Note: ... ]

Draft n3291 [11.3/2]:

  Declaring a class to be a friend implies that the names of private and 
  protected members from the class granting friendship can be accessed in 
  the base-specifiers and member declarations of the befriended class.
  [ Example: ... ]

As you can see, the normative relevant wording has _not_ changed with 
respect to visibility of names in nested classes. Aparently, the committee 
is of the opinion that the non-normative note in the C++03 standard was 
errorneous. Hence, one can argue, g++ and newer versions of Visual Studio 
are correct in _not_ rejecting your code even in strict c++03 mode; it was a 
bug in the standard and not in the compilers.


Best,

Kai-Uwe Bux

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c++


csiph-web