来自私人CRTP基地的回调

时间:2014-04-21 16:29:21

标签: c++

以下代码不起作用,因为您不能从私有基类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;
}

2 个答案:

答案 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;
 }