Are inner classes in C++ automatically friends?
Asked Answered
Z

5

90

If I define an inner class in C++, is it automatically a friend of the class that contains it? For example, is this legal:

class Outer {
public:
    class Inner {
    public:
        void mutateOuter(Outer& o);
    };

private:
    int value;
};

void Outer::Inner::mutateOuter(Outer& o) {
    o.value ++; // Legal?  Or not?
}

I ask because on some compilers I've tried (VS2003) this code won't work, but I've heard at least anecdotally that it does work on some compilers. I can't find a relevant section in the C++ spec about this, and if anyone can cite something specific that would say that it is or is not legal that would be great.

Zoubek answered 16/2, 2011 at 7:37 Comment(8)
Member functions of a nested class follow regular access rules and have no special access privileges to members of their enclosing classes.: publib.boulder.ibm.com/infocenter/comphelp/v8v101/…Stowe
@aaa- Thanks for the link, but this seems to only apply to IBM's compiler, which I know does take a few liberties with the spec (for example, allowing you to take the address of a label with the && operator). Sorry if I'm being a stickler on this one, but I teach a C++ programming course and want to be very certain of the answer before I tell anything to my students.Zoubek
I don't think so because if that was the case then we would not explicitly need to declare friend classes also within the class body. Just a declaration should suffice in that caseContinuo
@template AFAIK they specifically list non-standard extensions.Stowe
By the way, the question is not "is it a friend", but "does it have private access". (The former is sufficient, but not necessary.)Antiquity
@GMan- You're absolutely right. Thanks for pointing that out!Zoubek
See DR 45.Recitation
The standard has been revised, hence the either the accepted answer should be corrected or the correct answer should be revised.Almatadema
D
84

After having asked more or less the same question here myself, I wanted to share the (apparently) updated answer for C++11:

Quoted from https://mcmap.net/q/246118/-access-of-nested-classes-which-behave-like-friends-but-aren-39-t:

standard $11.7.1

"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"

and the usual access rules specify that:

"A member of a class can also access all the names to which the class has access..."

specific examples has been given in the standard:

class E {
    int x;
    class B { };

    class I {
        B b; // OK: E::I can access E::B
        int y;
        void f(E* p, int i) {
            p->x = i; // OK: E::I can access E::x
        }
    };
}
Damiondamita answered 7/2, 2013 at 19:41 Comment(3)
Fully agree. I think, the answer for this question should be revised, since the code presented in the question can compile correctly now. Here is the proof: linkDrysalter
gcc 4.8.2 has a bug which was only fixed in gcc 4.9.0. gcc.gnu.org/bugzilla/show_bug.cgi?id=59482Puparium
In short: yes for C++11 and onwards, but no for C++03 and backwards.Astereognosis
C
59

Until C++11 (i.e C++98 and C++03) : No.

In C++98 and C++03, nested class cannot access private and protected members of enclosing class by default.

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
   }
};

Since C++11: Yes.

The above restriction has been removed since C++11. Now the nested classes can access the private and protected members of the enclosing class:

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

Hope that helps.

Cervin answered 16/2, 2011 at 7:40 Comment(3)
@templatetypedef: I knew that nested class cannot access private members of enclosing class, but quoted the wrong reference. Anyway I corrected the reference!Cervin
After omitting g(), the code compiles fine with C++11 onwards. Should update answer.Almatadema
I tried compiling this code on xcode 9.2 using its default compiler (LLVM 9.0), and it did not compile. It fails at the line return p->y. It seems that accessing the parent class private members is okay, but accessing the children class private members from the parent class is not ok.Hoptoad
U
17

The standard seems to have changed the specification about the accessibility.

§11.8/1 in C++98 states:

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.

§11.8/1 in N1804(after TR1) states:

A nested class is a member and as such has the same access rights as any other member.

I think current C++ compilers obey newer specification.

Unbeaten answered 16/2, 2011 at 9:23 Comment(6)
A nested class is a member, but can nested class members be considered to be members of the enclosing class? It isn't obvious. The nested class itself (not its members) can access members of the enclosing class like this: class Enclosing {private: enum PrivateEnum {VALUE}; class Nested {/*accessing enclosing class' member type*/ PrivateEnum e;}; };.Walleyed
@SergeyTachenov: Hi. §11.8/1 in N1804 also states: The members of an enclosing class have no special access to members of a nested class; the usual access rules shall be obeyed. This statement didn't change from C++98. So, as for the access from enclosing class to nested class(the opposite of templatetypedef's question), the usual access rules apply.Unbeaten
@Ise, I'm not talking about access to members of a nested class, it's an entirely different issue. I'm just not sure if the "a nested class is a member" concept applies to the members of the nested class too. What about several levels of nesting then?Walleyed
@SergeyTachenov: Sorry, I misunderstood your comment. If you mean whether class A { int i; class B { struct C { void f( A* x ) { x->i = 0; } }; }; }; is allowed in the standard, I suppose allowing it is the standard's intent. VC8, g++3.4.5 and Comeau online allow it. But I cannot say definite thing. If you are concerned, I'd recommend to post that question in StackOverflow. Someone with more detailed knowledge than me will answer.Unbeaten
@Ise, sorry for putting irrelevant stuff in. Initially I was commenting on the quote from N1804: "A nested class is a member" - does this imply that members of the nested class are members of the enclosing class too? I mean, in class A {int i; class B {A *a; int f() {return a->i;} }; }; the class B is a member of the class A, but B::f() is a member of the class A::B, not A! But I've just found another quote from DR 45 that might clarify this: "A member of a class can also access all names as the class of which it is a member." In other words, B::f() "inherits" access right of the class B.Walleyed
@SergeyTachenov: I think your inference is right. The relationship between enclosing class and nested class is transitive probably. class A {int i; class B {A *a; int f() {return a->i;} }; }; VC8, g++3.4.5, ideone(gcc4.3.4) and Comeau online accept your above code :-)Unbeaten
Z
4

This answer pertains to the (outdated) C++03 specification. The accepted answer at this question is more up to date.

Well, I feel silly for asking this question now because I just found the relevant part of the spec that covers this: §11.8/1:

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

(My emphasis)

So it looks like no, inner classes do not have special access privileges.

Zoubek answered 16/2, 2011 at 7:46 Comment(4)
You are misunderstanding that paragraph. There is no 11.8.1, did you mean 11.8p1 (or "11.8/1")?Recitation
@Fred Nurk- Whoops, meant 11.8/1. Will fix.Zoubek
@Fred Nurk- Also, when you say that I'm misunderstanding it, did that refer to me interpreting it incorrectly, or just mislabeling it?Zoubek
and @Fred: templatetypedef is correct. Please see my post. I also quoted the example from Standard itself.Cervin
W
3

I don't the precise location off the top of my head, but I do recall reading through the specs and finding that any private data in a class is hidden from all other classes, including nested classes.

Basically, nesting a class defines a certain scope, not access priviledges.

Willy answered 16/2, 2011 at 7:40 Comment(1)
You're incorrect, but I'm only -1'ing because somehow, even with the quoted correct answer nearby, this got +1'd. @Voters, please read all the answers before you go voting willy-nilly.Antiquity

© 2022 - 2024 — McMap. All rights reserved.