3

Consider the following code:

#include <iostream>

class A{
    friend class C;
    int a{42};
};

class B: private A{
    friend class C;
};

class C: private B {
public:
    void print() {std::cout << a << '\n';}
};

int main() {
    C c;
    c.print();
}

According to this answer, the member variable A::a is "present" in all classes, but its visibility differ, i.e. is not visible in B or C unless we make B or C a friend of A. My question is why do I need to make C a friend of both A and B? I would've though the friend declaration in A would suffice. If I remove the friend class C; declaration from either A or B, the code fails to compile.

vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • 2
    The answer that the question links to correctly refers to **access**; this question incorrectly talks about **visibility**. They're two different things. `a` is visible throughout the hierarchy, but it's private in `A`, so without the `friend` declarations it's not accessible. – Pete Becker Feb 12 '19 at 19:42

1 Answers1

6

My question is why do I need to make C a friend of both A and B?

Without B declaring C has a friend, C wouldn't see B as inheriting A. Even though C would see A::a, it would not see B::a.

Indeed:

  • C inherits B, so anything public in B is accessible from C.
  • But B inherits privately from A. C being a friend of B makes C see this inheritance.
  • The access of A::a is private, so even though C sees A as its ancestor, it needs to be a friend of A to see A::a.
YSC
  • 38,212
  • 9
  • 96
  • 149
  • Thanks, but still `cout << A::a` in `C` won't work... And `C` inherits privately as well from `B`. – vsoftco Feb 12 '19 at 18:52
  • @vsoftco With only the friendship C<->A, `A::a` can't be accessed from `C`without an instance of `A`. It needs friendship B<->A to know it _is an_ `A` and it contains an `A::a`. – YSC Feb 12 '19 at 18:55
  • Ok this makes sense, although I though that even without accessibility levels the compiler knows the "is-a/has-a" relation anyway, but looks like it's not the case. At least that's the impression one gets reading [this answer](https://stackoverflow.com/questions/860339/difference-between-private-public-and-protected-inheritance/1372858#1372858) (even mentioned as IMPORTANT NOTE). – vsoftco Feb 12 '19 at 18:58
  • I take that back, seems that the compiler knows the is-a/has-a relationship only between child/parent, and not along a hierarchy. – vsoftco Feb 12 '19 at 19:23
  • 1
    "The visibility of A::a is private" -- no. The **access** of `A::a` is private. Visibility is not affected by accessibility. – Pete Becker Feb 12 '19 at 19:45
  • Thank you @Pete; I think I got mixed up by the verb "see" I use throughout the answer. Fixed. – YSC Feb 13 '19 at 14:08
  • It's a subtle distinction, and other languages (I'm looking at you, Java) do it differently. I'm considering writing a question and self-answer about the difference and why it matters. – Pete Becker Feb 13 '19 at 15:32
  • @Pete Please do so and link it there. – YSC Feb 13 '19 at 15:38