以下代码不起作用,因为您不能从私有基类static_cast
。
用C风格的演员表替换演员阵容(尽管我最初认为这会调用未定义的行为,显然它没有,请参阅this answer),但是相当丑陋,因为它还允许你绕过const检查另一种方法是让CRTPBase成为朋友,但这会暴露Derived的所有私人成员。
是否有另一种方法可以在不使用C风格的演员表而且不使CRTPBase成为朋友的情况下编写此内容?
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;
}
答案 0 :(得分:2)
不是理想的解决方案,但您可以将友谊限制为一种独特的方法,如下所示:
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() {}
};
答案 1 :(得分:2)
我认为最好的解决方案是避免私有继承,而是选择数据隐藏。 将成员函数标记为受保护将阻止除派生类之外的任何位置的访问。而是使用了进一步的公共继承奖励。
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;
}