C++ 派生模板类对象的实例化

C++ 派生模板类对象的实例化,c++,crtp,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(){

我将类模板用作派生类的基类。其想法是通过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;
};
有人能解释一下问题出在哪里吗? 非常感谢您。

BASE
实例中,没有
DER1
实例,只有
BASE
试图将自己转换为它不存在的东西


PS:关于C++内存模型是相当相关的,但是超出了我用简单的词解释的。 当您定义BASE类型的对象时,它只是一个BASE,但在它内部,您可以将this指针的大小写为this not is(DER1),并通过该无效指针继续使用它。这是未定义的行为,垃圾是正常的结果。CRTP工作的唯一时间是对象的动态类型实际上是传递给基类的模板参数。也就是说,如果BASE认为它真的是一个DER1,那么它一定是一个DER1。当DER1是唯一的基时将其自身强制转换为DER1,并将该指针用于DER1操作是未定义的行为,这与执行此操作没有太大区别:

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

您应该考虑使基础构造函数具有“受保护”访问级别,以防止使用不当的简单情况。这样,基构造函数只能由派生对象调用,因此您不会意外地孤立地实例化基:

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

  public:
    void write() {static_cast<T*>(this)->write(); }
};
模板
阶级基础
{
受保护的:
BASE()=默认值;
基本(基本常数&)=默认值;
公众:
void write(){static_cast(this)->write();}
};
然后,你得到的不是垃圾,而是:

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

error: 'BASE<T>::BASE() [with T = DER1]' is protected within this context
BASE<DER1> base;
BASE-objA;
objA.write();
错误:“BASE::BASE()[with T=DER1]”在此上下文中受保护
基地;

static cast只有在您实际上是一个基本子对象时才被定义……在
base
实例中没有
DER1
实例,只有一个
base
试图将自己强制转换为某个东西,而不是在其切片的最后。@tobi303答案区域在下面!!:-)。。。我找不到比你更好的措辞了。@skyjack我也是:P
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;