12

If I have two Classes as follows with inheritance:

class A
{
    ...
}

class B : public A
{
    ...
}

And a third class with defined as a friend class A:

class C
{
    friend class A;
}

Will I be able to access from class B (which is also an object of type A) all members of class C as if I had defined class B the friend Class in the first place?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Harry
  • 1,362
  • 12
  • 19
  • 2
    What happens when you try it? It will take less time for you to try it than it will for us to answer. – Robert Harvey Dec 12 '12 at 16:27
  • Sorry I should of added that I have tried and it doesn't work which I thought was surprising... – Harry Dec 12 '12 at 16:28
  • Doesn't work, meaning you were not able to access from class B all members of class C? – Robert Harvey Dec 12 '12 at 16:33
  • 1
    Call it nitpicking if you like, but B is not an object of class A. It inherits from A. – Masked Man Dec 12 '12 at 16:34
  • @RobertHarvey Yes as in if I try to access protected/private members of class C from a function of class B, I get a "not visible" error. I guess this answers my question but I was looking for a reason... – Harry Dec 12 '12 at 16:45

8 Answers8

24

friendship is neither inherited nor transitive. It is strictly one-one relationship between two classes.

class A {
  friend class B;  
  int Aries;
};

class B {
  friend class C;  
  int Taurus;
};

class C {
  int Leo;
  void Capricorn() {
    A a;
    a.Aries = 0;  // this wont work, C is not a friend of A.
                // friendship is not transitive
  }
};

class D : public C {
  void Gemini() {
    B b;
    b.Taurus = 0;  // this wont work, D is not a friend of B.
                   // friendship is not inherited
  }
};    

class E : public B {
  void Scorpio() {
    C c;
    c.Leo = 0; // this wont work either, friendship is not inherited
  }
};

Reference: "The C++ Programming Language" Bjarne Stroustrup

More explanation (mine): If friendship were not one-one, it would be the end of encapsulation. Note that B class can access private members of A only if the class declaration of A declares B as friend. B cannot enforce friendship on A.

Now, if friendship could be inherited, then someone just needs to inherit B to access private members of A, without A having any say in preventing it. Also, allowing friendship to be transitive would lead to other problems, since now B could have a friend C, who in turn could have a friend D, all the way to Z. All of B, C, D, ..., Z can now access A's private members, which would be a disaster.

Masked Man
  • 1
  • 7
  • 40
  • 80
6

For some reason everybody has forgotten that you can access virtual private functions of a class that derives from the friendship-giver.

#include <iostream>

class Friend;
class Parent
{
    friend class Friend;
private:
    virtual void nameYourself() { std::cout << "Parent" << std::endl; }
};

class Child : public Parent
{
private:
    virtual void nameYourself() { std::cout << "Child" << std::endl; }
};

class Friend
{
public:
    void foo(Parent *p) { p->nameYourself(); }
};

int main()
{
    Parent p;
    Child c;
    Friend f;
    f.foo(&p);
    f.foo(&c);
    return 0;
}

The output of running above code is:

Parent
Child

The reason why it works is tricky and has to do with how this pointer is passed (look up vtables). Were you to remove "virtual" keyword from the function declaration and you will lose this ability.

v010dya
  • 5,296
  • 7
  • 28
  • 48
  • 1
    I believe OP asked how to access `Friend`'s private member from `Child`, not how to access `Child`'s private member from `Friend`. – azalea Dec 27 '18 at 20:49
3

To quote the standard, C++11 11.3/10:

Friendship is neither inherited nor transitive.

Meaning that neither derived classes of friends nor friends of friends receive the benefits of friendship.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
2

One more example adding to Masked Man's answer/code above that I found useful:

class B {
  friend class F;
  friend class E;
  int Taurus;
};

class E : public B {
  int Egg;
};

class F {
    void Foo () {
       B b;
       b.Taurus = 4;  //Works F is friend of B (of course)
       E e;
       e.Taurus = 6; // Works E is derived from B and F is friend of B 
                  // Taurus is private member of B.
       e.Egg = 5; // Does not work, F is friend of Base Class B but not
               // E, so can't access members of the derived class
    }
};
Donald Duck
  • 8,409
  • 22
  • 75
  • 99
Viral Shah
  • 71
  • 2
1
  • No - it is not inherited (see below); if B is a subclass of A and C is a friend of A, B doesn't have access to C's private members, including the inherited members.
  • Likewise, if A is a friend of C, or if both A and C are mutually friends of each other, this does NOT give B access to C's private members, including the inherited members.
  • This URL states the subclasses of friend classes don't inherit the friend associations:

    C++ friend inheritance?

  • This applies to BOTH "associations (both the main class' own and other classes friended with the main class)" - the question is for the latter case here.

Community
  • 1
  • 1
A B
  • 4,068
  • 1
  • 20
  • 23
0

I think it depends. You will have access from the A part of B (the sliced part). If you’ve defined B’s own function, I think you won’t.

phaazon
  • 1,972
  • 15
  • 21
0

I didn't understand what you are trying to do, but B is a superclass of A. Is not an object. Between B and C there isn't any inheritance relationship

Daniele
  • 821
  • 7
  • 18
  • No. Here A is a superclass of B. I realise there isn't any inheritance between B and C, only friendship. – Harry Dec 12 '12 at 16:46
0

No, you can't call C class methods directly, but you can access them by pointer. A class should be modified:

class C
{
  void method()
  {
  }
  friend class A;
};

class A
{
protected:
  constexpr static void (C::*f)() = &C::method;
};

class B : public A
{
  B()
  {
    //C().method(); ← This wont work
    (C().*f)(); // ← This works fine
  }
};

Accessing data members and static data are simple too

dyomas
  • 700
  • 5
  • 13