Are Inner Classes in C++ Automatically Friends

Are inner classes in C++ automatically friends?

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://stackoverflow.com/a/14759027/1984137:

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

Do nested classes obtain friendship relations of outer class?

The standard is pretty clear that friendship is not inherited:

14.3/10: "Friendship is neither inherited nor transitive"

But a nested class is not inheritance. It is a member. If a class is a friend, its members have access to the class's friends. Therefore, the inner/nested class has access.

Straight from the standard:

14.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:

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

Given a class and its friend class, are the latter's inner classes automatically friends to the former class?

I think there are two issues at play here. One is that the code smells bad, as you say, and the second is that it doesn't compile on your system. Regarding the smell, yes, excessive use of the friend keyword often indicates bad OO design. It is generally better to give an object what it needs to do its job rather than pull something out of it, which is essentially what friend lets you do.

Large numbers of inner classes, IMO, are not that bad, as they merely serve to keep classes within the scope of another. This helps keep the namespace less cluttered and allows you to use common names across different functional areas.

Regarding the compilation issue, I tried to reproduce this on my system (Ubuntu 10.04, gcc 4.4.3, two years old at this point), and created this sample program:

class A
{
friend class B;

int x;
};

class B
{
class Inner
{
public:
void foo(A& a)
{
a.x++;
}
};

public:
void bbb()
{
Inner i;
A a;

i.foo(a);
}
};

int main()
{
B b;

b.bbb();
}

This compiled with no errors or warnings. I initially had nothing marked public, but I needed to add bbb() to create an instance of class Inner, and I had to add a public method of Inner so I could invoke it to do something with an A.

The upshot is that I think your development system is out of date. The main developers clearly have no problem compiling their code, so the difference has to be with your system, or else they have configured their systems in a way that they are not telling you about. That being said, I think they could do more to make their code more portable and easier to build. In an open source project, that is to be expected if you want others to contribute.

Access of nested classes (which behave like friends, but aren't)

because nested class is a member of the enclosing class

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

Are inner struct/class declarations automatically friend of the nesting class?

They're not friends per se (so your interpretation is subtly wrong), but the effect you've seen is definitely standard-mandated:

[C++11: 11.7/1]: A nested class is a member and as such has the same access rights as any other member. [..]

The example given at this point in the standard is similar to yours.

However, this was not legal in C++03!

[C++03: 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. [..]

This was considered to be a defect in the standard as early as 1998 (and made into DR #45 in 2001), which may go some way to explaining why you're seeing non-compliant behaviour in GCC, pre-C++11. In that sense, we might see the new C++11 wording as catching up with a long-standing practical reality.

If class Outer is my friend, is class Outer::Inner too?

[class.access.nest]/1 states that

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

So I believe yes, this is standard behavior.

Let's say that Outer has a member function foo(). That function, of course, will have access to Bob's members. To my understanding, the part that I quoted implies that any nested class inside Outer would have the same access rights as foo(), thus having the ability to access Bob's members.

It is also worth noting that the standard contains the following example ([class.friend]/2), note the usage of A::B in Y:

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

Inner class private member access and enclosing's friendness

You can't.

You seem to think that because _bla is an object of bla and bla is the outer class that you can access private fields of inner outside of bla. This is not the case.

Access modifiers work on scope, not on the objects you're operating on. You can access the private fields of inner in the class body of bla (in its methods etc). Not outside of it.

C++ - What's the point of nested classes?

I'm studying a little of C++ and now I'm fighting against it's similitudes with Java.

First of all be aware that C++ nested classes are similar to what in Java you call static nested classes. There isn't anything in C++ syntax to reproduce Java nested classes.

I discover that private attributes of "container" class are not visible by inner class...

C++ 98

In C++ inner classes aren't different to normal classes, they're not class members then they can't access container class' private members (unlike other languages like Java or C#).

C++ 03

Nested classes are class members but restrictions on what they can access still applies (see also section Weird things at the end of this answer). It has been considered a standard defect (see DR45) then some compilers earlier implemented C++0x access rule earlier even when compiling for C++03 (notably GCC, thanks to Jonathan Wakely to spot this out).

C++ 11

This rule changed in C++ 11, now nested classes can access private member of container class. From §11.7:

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

Of course you still need an instance to access non static members.



...so why I should use them?

They're then an implementation detail to group related classes and they have same issues about their usage that you may have in other languages (clarity for newbies, primary). Their greatest benefit IMO is encapsulation, if for example you have this:

class stream {
virtual void write(const std::string text) = 0;
};

class channel {
public:
virtual stream* get_stream() = 0;

// Other methods...
};

class tcp_channel : public channel {
public:
virtual stream* get_stream() {
return new tcp_stream(this);
}

private:
class tcp_stream : public stream { /* implementation */ };
};

They're also helpful in some circumstances to substitute nested namespaces:

class protocol {
public:
virtual void create_connection() = 0;

class tcp : public protocol { /* implementation */ };
class shared_memory : public protocol { /* implementation */ };
class named_pipes: public protocol { /* implementation */ };
};

auto media = protocol::tcp();

Or to hide implementation details:

class file_system_entry {
public:
class file : public file_system_entry { };
class directory : public file_system_entry { };

std::time_t get_last_modified() { ... }

void remove() { ... }
virtual void copy_to(std::string path) = 0;

private:
class local_handle {
// Implementation details
} _handle;
};

There are many others usage patterns (see also Why would one use nested classes in C++? for a much better discussion), just remember not everyone will correctly understand (and use!) them. See also Pros and cons of using nested C++ classes and enumerations?

Also, is there a way to make visible those attributes?

Before C++ 11 you can't (of course unless you declare them as friends but see next paragraph), if you need this feature just use a C++ 11 compiler (that supports this feature). GCC does (from long time ago) and also MSVC does, I don't know about other compilers.

Nested Friends

Is there any difference between C++ 11 access rules and friend classes? In general they're almost equivalent (automatic access is just less verbose):

class container {
public:
class nested;
friend class nested;

class nested { };
};

Compared to:

class container {
public:
class nested { };
};

However with forward declaration you have some side effects. Also remember that from accessibility point of view they're equivalent (access, like friendship, is not inherited nor transitive). These examples don't compile:

class external : public container::nested {
public:
// No: only class declared inside "container"
// has access to private members, we do not inherit that
void foo(container obj) { /* access a private member of obj*/ }
};

// No, "container" has not access to "nested" private members,
// visibility isn't reciprocal
void container::foo(container::nested obj) {
// Access some private member of obj
}

// No, we don't have anything to do with container,
// visibility isn't transitive
void friendOfNested(container obj) {
// Access some private member of obj
}

Are then completely equivalent? No, because private members of container's friends are accessible in nested if it's a nested class in C++ 11 but they're not if nested is a friend of container. Given this outlined structure:

class container;

class another {
friend class container;
};

class container {
public:
class nested { };
};

nested can access another's private members:

void container::nested::foo(another obj) {
obj.somePrivateMember = 0;
}

It works because nested is a member of container then transitive restriction of friendship doesn't apply. Before C++ 11, declaring nested as friend of container, that code won't compile because friendship isn't transitive.

Weird things

We'd assume we can always declare a nested class as friend of its container? Actually standard said (SO/IEC 14822:2003(E), 11.8):

A friend of a class is a function or class that is not a member of the class...

Then we shouldn't be able to declare nested as friend of container: in C++ 03 nested classes are class members (but standard explicitly said they have no access to container privates and also they can't be friends of container class). It seems there was no hope, fortunately most compilers allowed us to do so (regardless to what standard said).

Are friends supposed to be transitive in nested classes?

In C++03, nested class cannot access private and protected members of enclosing class by default (see §11.8/1). But if you make them friend of the enclosing classs, then they can access them. But again nested class of nested class is still not friend of the outermost enclosing class, the nested class of the nested class cannot access private and protected members of the outermost enclosing class; it cannot even access the private and protected member of the immediate enclosing class, as noted earlier. What you're doing is that, hence that is not allowed.

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

Its a defect in the C++03 Standard.

By the way, its a defect in the C++03 Standard. Since the nested class is a member, it should have access to private and protected members, just like any other member:

§9.2/1 (C++03):

Members of a class are data members, member functions (9.3), nested types… Nested types are classes (9.1, 9.7) and enumerations (7.2) defined in the class…

See this Defect Report :

  • 45. Access to nested classes


Related Topics



Leave a reply



Submit