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 instance of the derived class.
If the inheritance is changed to private
then compilation fails.
In short, how is d.b_var
valid within F::func(D& d)
?
#include <iostream>
#include <string>
using namespace std;
class B{
int b_var;
friend class F;
};
class D: public B{
int d_var;
};
class F{
public:
void func(D &d){
d.b_var = 5;
}
};
int main()
{
cout<<"fine";
}
D
is aB
when public inheritance is used. So accessingb_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.
Object of
class D
is composed of 2 separate parts :That why the concept of object slicing works when we do:
Now we can access from inside
object of class D
, thepart containing members of B
viaobjB
. Compiler remembers or can distinguish between the two parts insideclass D
. So compiler know what is being accessed via what.The statement
friend class F;
insideclass B
simply tells thatmember functions of class F
can accesses theprivate, protected and public
members ofclass B
. That is, formember functions of class F
all the members ofclass B
arepublic
.Actually, inside every class there are three sections w.r.t accessibility:
So when we declare some
class B
:then following 3 sections get created inside class
B
as shown above.Now when we declare some
class F
to be afriend
ofclass B
:then the compiler creates the sections as follows:
Note that
int a;
andint b;
are now public formember functions
ofclass F
.Now when
class D
is derivedpublicly
fromclass B
then thepublic
section ofclass B
becomespublic
section ofclass D
. Similary, theprotected
section ofclass B
becomesprotected
section ofclass D
. Therefore, thepublic
section part ofclass B
can be accessed via object ofclass D
. And sinceB::a;
andB::b;
are in public section formembers functions of class F
, thereforeB::a
andB::b
can be accessed via object ofclass D
. Also note that although after derivationint a;
andint b;
become members ofclass D
, still compiler is able to distinguish them and considers them apart of class B
.Now when
class D
is derivedprivately
fromclass B
then thepublic
section ofclass B
becomesprivate
section ofclass D
. Similary, theprotected
section ofclass B
becomes protected section ofclass D
. Therefore, now thepublic
section part inside ofclass B
cannot be accessed via object ofclass D
. Recall that inclass B
,B::a;
andB::b;
are originally in public section formembers functions of class F
but afterprivate
derivation, the members ofclass B
i.eB::a
andB::b
are now in private section ofclass D
. Therefore,B::a
andB::b
cannot be accessed via object ofclass D
. Also note that although after derivationint a;
andint b;
become members ofclass D
, still compiler is able to distinguish them and considers them apart of class B
. After derivation the accessibility and rules of some members ofclass 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?You write:
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:
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:
d.b_var
might be misleading. To be more precise (another way to see it),b_var
is not (direct) member of derived classD
. Instead, the object ofD
contains a subobject of base classB
, which has memberb_var
, and could be accessed by the friendF
. (As we can also writed.b_var
asd.B::b_var
.)$10/3 Derived classes [class.derived]:
And
Because
Then
Note that in last case, even
F
is friend of classD
, it could access all the private/protected members ofD
, but not including members in subobjectB
, because they're not (direct) members of classD
.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 thisIt 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 fromD
.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.