【问题标题】:CRTP to avoid code duplication : can't assignment Base=Derived by valueCRTP 避免代码重复:不能赋值 Base=Derived by value
【发布时间】:2017-03-07 10:03:53
【问题描述】:

我有 BaseDerived1Derived2 等课程。
它是可编译的(下)。

class Base{  };
class Derived1 : public Base{
    public: Derived1* operator->() { return this; }
    public: void f1(){}
};
class Derived2 : public Base{
    public: Derived2* operator->() { return this; }
};
class Derived3 : public Derived2{
    public: Derived3* operator->() { return this; }
};
int main(){//test case (my objective is to make all these work)
    Derived1 d1;  d1->f1();
    Base b=d1;              //non harmful object slicing
    Derived3 d3;
    Derived2 d2=d3;
}

编辑:我相信是a non-harmful object slicing,我认为它与问题无关。

然后,我希望operator->()Base 中,所以我不必在所有DerivedX 类中实现。

这是我迄今为止的尝试,使用CRTP。在# 无法编译:-

class Base{  };
template<class T1,class T2>class Helper{
    public: T2* operator->() { return static_cast<T2*>(this); }
};
class Derived1 : public Helper<Base,Derived1>{
    public: void f1(){}
};
class Derived2 : public Helper<Base,Derived2>{    };
class Derived3 : public Helper<Derived2,Derived3>{    };
int main(){
    Derived1 d1;  d1->f1();
    Base b=d1;                    //#
    Derived3 d3;     
    Derived2 d2=d3;
}

我已经阅读了这两个有希望的链接(下),但进展不大(上):-

Wiki 说要转换Derive to Base is quite impossible for CRTP,所以我觉得使用 CRTP 可能没有解决方案。

问题:

  • 如何将operator-&gt; 移动到某种基类以避免代码重复?
    (有无 CRTP 都可以)
  • 有没有使用 CRTP 的解决方案?也就是说,CRTP 不适合这份工作吗?

我是 CRTP 的新手(今天就玩一下)。如有重复请见谅。

【问题讨论】:

  • 首先你需要了解object slicing。那么对于您的问题,只是在第二个示例中,派生类不是从Base 派生的。继承是一种“is-a”关系,但例如Derived1不是Base,而是Helper&lt;Base,Derived1&gt;
  • @Some 程序员老兄关于“is-a”:是的,关于这个的 wiki 状态。我明白。这就像 CRTP 的直接缺点。有什么解决方法吗? ....... 关于对象切片:在这种特定情况下,我并不害怕切片(主要)。我接受我收到了一些编译器警告。 :)
  • 解决方法是修改Base类。不要发明一些Helper 类。但它仍然不适用于您对 b 对象的初始化,因为 b 不是 Derived1 对象而是 Base 对象,铸造将是错误的。如果您尝试b-&gt;f1(),您将有未定义的行为(如果它甚至构建)。
  • @Some 程序员老兄 谢谢!顺便说一句,我想要d1-&gt;f1() 而不是b-&gt;f1()。我只想上调。对不起,如果我的变量名称令人困惑。
  • 使Helper&lt;T1, T2&gt; 派生自T1 - 然后Derived1 等人实际上将派生自Base(间接)。不过,我不清楚 Base 类的目的是什么,以及为什么所有 DerivedX 都继承自它很重要。

标签: c++11 inheritance polymorphism crtp


【解决方案1】:

抛开你的对象的切片,如果你将你的助手定义为,你的例子就可以正常工作:

template<class T1, class T2>
class Helper: public T1 {
public:
    T2* operator->() {
        return static_cast<T2*>(this);
    }
};

即:

  • T1 派生,就好像在纯基于 mixin 的方法中一样
  • 使用 T2 就像在纯 CRTP 方法中一样

如果考虑Derived1的声明:

class Derived1: public Helper<Base, Derived1>;

不用说现在Base b = d1; 有效,因为Derived1 直接继承自Base

【讨论】:

  • 这需要时间来消化,但我坚信这是一个正确的解决方案。这种 CRTP 方法有什么具体的技术术语吗? ...看起来很酷。
  • @javaLover 为什么这么难消化?您需要一个从其第一个模板参数继承并使用第二个模板参数添加 crtp 内容的中间类模板。你只是忘了做第一步到最后。否则T1 的目的是什么?在您的示例中未使用它,对吗?
  • 同意,我只是觉得头晕。 XD
  • @javaLover Ahahah。它发生了。无论如何,这个成语被称为mixininheritance from above。如答案中所述,您将它和crtp混为一谈。
  • 哇,谢谢。我刚刚找到了自己的wiki page
猜你喜欢
  • 2014-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多