The following code doesn't work, as you can't static_cast
from private base class.
Replacing the cast with a C-style cast works (although I originally thought this would invoke undefined behaviour apparently it does not, see this answer), but is rather ugly as it also allows you to bypass const-checking, etc. The other approach would be to make CRTPBase a friend, but that would expose all of Derived's private members.
Is there another way of writing this without using a C-style cast and without making CRTPBase a friend?
template<typename T>
struct CRTPBase {
void callBase() {
T * derived = static_cast<T*>(this);
derived->publicMethod();
}
};
struct Derived : private CRTPBase<Derived> {
void callParent() { this->callBase(); }
void publicMethod() {}
};
int main() {
Derived d;
d.callParent();
return 0;
}
I think the best solution is to avoid private inheritance and instead opt for data hiding. Marking the member function protected will prevent access from everywhere except derived classes. A further bonus public inheritance is used instead.
template<typename T>
class CRTPBase {
protected:
void callBase() {
T * derived = static_cast<T*>(this);
derived->publicMethod();
}
};
struct Derived : public CRTPBase<Derived> {
void callParent() { this->callBase(); }
void publicMethod() {}
};
int main() {
Derived d;
d.callParent();
d.callBase() // <- illegal
return 0;
}
Not an ideal solution, but you can restrict the friendship to a unique method as follow:
template<typename T>
struct CRTPBase {
friend T; // So T can see asDerived.
void callBase() { asDerived()->publicMethod(); }
private:
T* asDerived() { return static_cast<T*>(this); }
};
struct Derived : private CRTPBase<Derived> {
friend Derived* CRTPBase<Derived>::asDerived();
void callParent() { this->callBase(); }
void publicMethod() {}
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With