In your example, the parameter type S in foo2 is C1 . A friendly relationship exists between T2<S> and T1<S> . Although C1 comes from T1<C1> , he does not become a friend of all friends of T1<C1> .
In the expression pT1->bar , bar is in C1 and, since friendship is not passed to the derived class, it is private.
Your example uses virtual functions, so this can be fixed by explicitly referring to bar , which is a friend of our class:
void foo2(S *pT1) { pT1->template T1<S>::bar(); }
Access check is now verified.
The reference to this in the '03 C ++ standard is at 11.4 / 10, where it simply says:
Friendship is neither inherited nor transitive.
Thanks to Potatoswatter for his comment. Using qualified-id for id-expession , we will disable virtual sending (5.2.2 / 1):
If the selected function is not virtual, or if the id expression in the class member access expression is a qualification identifier, this function is called.
We can add a non-virtual dispatcher, or we can first convert the parameter to the base type, and then make a call:
void foo2(S *pT1) { static_cast< T1<S>* > (pT1)->bar(); }
Virtual sending is now performed as needed.