Search code examples
c++inheritanceprivatefriend

Can a friend class object access base class private members on a derived class object?


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

Solution

  • 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?