I\'m surprised that the code below compiles.
It seems that a class befriended to the (publicly inherited) base class can access a member of the base class provided an in
Object of class D
is composed of 2 separate parts :
part containing members of B
part containing members of D
That why the concept of object slicing works when we do:
D objD;
B objB = objD;
Now we can access from inside object of class D
, the part containing members of B
via objB
. Compiler remembers or can distinguish between the two parts inside class D
. So compiler know what is being accessed via what.
The statement friend class F;
inside class B
simply tells that member functions of class F
can accesses the private, protected and public
members of class B
. That is, for member functions of class F
all the members of class B
are public
.
Actually, inside every class there are three sections w.r.t accessibility:
public
protected
private
So when we declare some class B
:
class B
{
public:
int a;
protected:
int b;
public:
int c;
};
then following 3 sections get created inside class B
as shown above.
Now when we declare some class F
to be a friend
of class B
:
class B
{
friend class F;
private:
int a;
protected:
int b;
public:
int c;
};
then the compiler creates the sections as follows:
class B
{
friend class F;
private:
int a;
protected:
int b;
public:
int c;
//int a; only for member functions of class F
//int b; only for member functions of class F
};
Note that int a;
and int b;
are now public for member functions
of class F
.
Now when class D
is derived publicly
from class B
then the public
section of class B
becomes public
section of class D
. Similary, the protected
section of class B
becomes protected
section of class D
. Therefore, the public
section part of class B
can be accessed via object of class D
. And since B::a;
and B::b;
are in public section for members functions of class F
, therefore B::a
and B::b
can be accessed via object of class D
. Also note that although after derivation int a;
and int b;
become members of class D
, still compiler is able to distinguish them and considers them a part of class B
.
Now when class D
is derived privately
from class B
then the public
section of class B
becomes private
section of class D
. Similary, the protected
section of class B
becomes protected section of class D
. Therefore, now the public
section part inside of class B
cannot be accessed via object of class D
. Recall that in class B
, B::a;
and B::b;
are originally in public section for members functions of class F
but after private
derivation, the members of class B
i.e B::a
and B::b
are now in private section of class D
. Therefore, B::a
and B::b
cannot be accessed via object of class D
. Also note that although after derivation int a;
and int b;
become members of class D
, still compiler is able to distinguish them and considers them a part of class B
. After derivation the accessibility and rules of some members of class B
have changed.
Since this question somewhat relates to effect of public, protected and private
derivation, therefore for completeness please see:
Why can a derived class not access a protected member of its base class through a pointer to base?
- It seems that somehow friendship is inherited and a friend class can access a member of the derived class.
In short, how isd.b_var
valid withinF::func(D& d)
?
d.b_var
might be misleading. To be more precise (another way to see it), b_var
is not (direct) member of derived class D
. Instead, the object of D
contains a subobject of base class B
, which has member b_var
, and could be accessed by the friend F
. (As we can also write d.b_var
as d.B::b_var
.)
$10/3 Derived classes [class.derived]:
The base-specifier-list specifies the type of the base class subobjects contained in an object of the derived class type. [ Example:
struct Base { int a, b, c; }; struct Derived : Base { int b; }; struct Derived2 : Derived { int c; };
Here, an object of class
Derived2
will have a subobject of classDerived
which in turn will have a subobject of classBase
. — end example ]
And
- If the inheritance is changed to
private
then compilation fails.
Because
class B {
int b_var;
friend class F;
};
class D: private B {
int d_var;
};
class F{
public:
void func(D &d) {
d.b_var = 5; // Fail. Can't access subobject of B
d.d_var = 5; // Fail. Can't access member of D
}
};
Then
class B {
int b_var;
};
class D: private B {
friend class F;
int d_var;
};
class F{
public:
void func(D &d) {
d.b_var = 5; // Fail. Can't access b_var of subobject of B
d.d_var = 5; // Fine.
}
};
Note that in last case, even F
is friend of class D
, it could access all the private/protected members of D
, but not including members in subobject B
, because they're not (direct) members of class D
.
D
is a B
when public inheritance is used. So accessing b_var
is still perfectly legal.
You would get an error, however, if you attempt to access d_var
, since the friendship itself is not inherited, as you seem to be aware.
Inheritance always makes all members of the base be members of the derived. Access specifiers only affect where an identifier is visible. That's why accessing a private member illegally produces a different error to accessing an identifier that doesn't exist.
While there already are good answers I think some images would help here a bit too.
This is an abstraction of your B
class. F
has access to all its members.
When you now instantiate a D
object it looks like this
It still is a B object but also a D object. It extends B
so to speak. F
can still access the part from B because it's still there but not from D
.
Please note that these abstractions do not really display the layout in memory and explain overriding etc. But they are just for the sake of this question.
You write:
It seems that somehow friendship is inherited and a friend class can access a member of the derived class.
But it rather should be:
It seems that a class befriended to the (publicly inherited) base class can access a private member of the base class provided an instance of the derived class.
Or:
It seems that a class befriended to another class can access the private members of its instances.
This relates to your question:
In short, how is
d.b_var
valid withinF::func(D& d)
?
Because d.b_var
is a member of an instance of class B (via polymorphism) to which instances of class F have access (via friend-status).
This doesn't work with d.d_var
, because the friendship to the base class is not inherited and instances of class F therefore don't have access to private members of d.
This doesn't work with private (or protected) inheritance, because thereby another "layer of access restriction" is added. In addition, you then need to grant access to the derived class' privately inherited members as well (which d.b_var
then is). For example by making also D a friend to F.
For reference: