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

时间:2015-05-04 15:20:38

标签: c++ polymorphism

我有一个Base类,它包含一个成员变量std :: unique_ptr<基数>下一个。我有几个派生类Base。

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

通过Base :: grow()中的虚函数调用保证了下一个正确类型。

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

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

#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

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

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

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

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

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:0)

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

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