I am trying to implement a CRTP hierarchy of classes. I am interested in the base class to have access to the data member of a derived class down the chain:
#include <iostream>
template <class Derived>
class A {
public:
void showv() {
std::cout << static_cast<const Derived*>(this)->v << std::endl;
}
};
template <class Derived>
class B : public A< Derived > {
typedef A<Derived> base;
friend base;
};
class fromA : public A<fromA> {
typedef A<fromA> base;
friend base;
protected:
int v = 1;
};
class fromB : public B<fromB>
{
typedef B<fromB> base;
friend base;
protected:
int v = 2;
};
int main()
{
// This runs ok
fromA derived_from_a;
derived_from_a.showv();
// Why doesn't the following compile and complains about the protected member?
fromB derived_from_b;
derived_from_b.showv();
return 0;
}
Although the first derived class (fromA
) compiles and runs as expected, the second (fromB
), that derives from a class derived fromA
, doesn't.
The issue is: the friend of my friend is not my friend.
In fromA
you have
typedef A<fromA> base;
friend base;
Which makes A<fromA>
a friend and show
can access fromA
's protected member.
In fromB
you also have
typedef B<fromB> base;
friend base;
But this doesn't make A
a friend, it makes B
your friend. Even though A is a friend of B
it does not mean it is also now a friend of fromB
and this is why you cannot access v
in show
.
One way you can fix this is to make typedef A<Derived> base;
public or protected in B
and then in fromB
you can add friend base::base;
which would give A
access.