将多态成员变量实例化为适当的类型

Instantiate polymorphic member variable to be of appropriate type

我有一个Baseclass,里面有一个成员变量std::unique_ptrnext。我有几个派生的 classes of Base.

我有一个非虚拟函数 Base::grow() ,它接下来会初始化。 next 将总是 指向调用grow 的对象类型的对象。

通过 Base::grow() 中的虚函数调用可以保证 next 是正确的类型。

为每个派生的 class 创建一个虚函数既麻烦又容易出错,因此我的问题是:我可以更简洁地做到这一点吗?

我当前的最小工作示例如下所示:

#include <iostream>
#include <memory>

class Base{
  public:
    static const unsigned SIZE = 3;
    std::unique_ptr<Base> next;
    void grow(unsigned index){
      if (index < SIZE){
        print();
        next = get_new();
        next.get()->grow(index + 1);
      }
    }

    virtual std::unique_ptr<Base> get_new(){
       return std::unique_ptr<Base>(new Base());
      //return std::move(std::unique_ptr<Base>(new Base())); (move not nec. see comments)
    }

    virtual void print (){
      std::cout << "a Base ";
    }
};

class Derived: public Base{
  public:
    virtual void print (){
      std::cout << "a Derived ";
    }
    virtual std::unique_ptr<Base> get_new(){
      return std::unique_ptr<Base>(new Derived());
    }
};

int main(){
  std::unique_ptr<Base> b;
  b = std::unique_ptr<Base> (new Base());
  b->grow(0);

  std::unique_ptr<Base> c;
  c = std::unique_ptr<Base> (new Derived());
  c->grow(0);
}

输出正确:a Base a Base a Base a Derived a Derived a Derived

总而言之:我想要一个可以消除繁琐的解决方案 get_new,我希望 Base::grow 根据调用对象的类型来确定要创建的类型。我考虑过使用 decltype,但没有成功。

与在 运行 时尝试确定类型相关的代码片段:

typedef std::remove_reference<decltype(*this)>::type DynamicBase;
next = std::unique_ptr<DynamicBase>(new DynamicBase()); 

上面的 DynamicBase 始终被确定为 Base,即使 this 是指向 Derived

的指针也是如此

你想要的是不可能的:你需要至少一个虚函数调用,即在每个派生中重写的虚方法。例如,考虑在另一个编译单元中定义派生的 class 的情况。如果不使用多态性,基class的代码将如何获得一个新的未知类型的派生对象?

昨天我第一次遇到奇怪的重复模板模式 (crtp),我相当确定它可以用于 get_new 只定义一次。

这里很好地解释了crtp的思想:https://katyscode.wordpress.com/2013/08/22/c-polymorphic-cloning-and-the-crtp-curiously-recurring-template-pattern/