派生模板类对象的实例化

时间:2017-08-25 17:44:24

标签: c++ crtp

我有类模板作为派生类的基类。这个想法是利用静态多态性"静态多态"通过CRTP技巧。

#include <iostream>
template <typename T>
class BASE
{
  public:
    void write() {static_cast<T*>(this)->write(); }
};

class DER1 : public BASE<DER1>
{
  public:
    void write(){
       std::cout << "Calling write() inside DER1 " << number << std::endl;}   
  private:
    int number = 11;
};

我尝试了两种不同的实例化派生类对象的方法,并且我发现这两种方法中的一种方法不正确。但我无法理解为什么。

int main(void) {

    BASE<DER1> der1_objA ;
    der1_objA.write();

    DER1 der1_objB ;
    der1_objB.write();
    return 0;
}

事实上,我得到了输出

Calling write() inside DER1 1880535040    [ random number]
Calling write() inside DER1 11            [correct number ]

有人可以解释我的问题在哪里吗? 非常感谢你提前。

2 个答案:

答案 0 :(得分:2)

BASE<DER1>实例中没有DER1实例,但只有BASE试图将自己投射到不是它的东西。

PS:this talk关于c ++内存模型是非常相关的,但是超出了我用简单的单词解释的内容。

答案 1 :(得分:1)

当你定义一个BASE类型的对象时,它只是一个BASE,但在它里面,你指的是它不是(DER1)的东西,并继续使用它通过那个无效指针。这是未定义的行为,垃圾是正常的后果。 CRTP工作的唯一时间是对象的动态类型实际上是传递给基类的模板参数。也就是说,如果BASE认为它确实是DER1,它实际上必须是DER1。当它仅为BASE并且使用该指针进行DER1操作时将其自身转换为DER1是未定义的行为,与此相同:

int x = 42;
std::string * sptr = (std::string*)&x; // extremely questionable
sptr->clear(); // undefined behavior

您应该考虑让BASE构造函数具有&#34; protected&#34;访问级别,以防止简单的滥用情况。这样,基础构造函数只能由派生对象调用,因此您不能意外地单独实例化基础:

template <typename T>
class BASE
{
  protected:
    BASE() = default;
    BASE(BASE const&) = default;

  public:
    void write() {static_cast<T*>(this)->write(); }
};

然后你得到:

而不是垃圾
BASE<DER1> objA ;
objA.write();

error: 'BASE<T>::BASE() [with T = DER1]' is protected within this context
BASE<DER1> base;