简体   繁体   中英

Instantiate polymorphic member variable to be of appropriate type

I have a Base class which contains a member variable std::unique_ptr< Base > next. I have several derived classes of Base.

I have a non-virtual function Base::grow() which initialises next. next will always point to an object of the type of the object calling grow.

That next is of the correct type is guaranteed via a virtual function call within Base::grow().

Creating a virtual function for each derived class is cumbersome and bug prone, hence my question: can I do this more succintly ?

My current minimal working example looks like this:

#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);
}

Output is correct : a Base a Base a Base a Derived a Derived a Derived

In summary: I'd like a solution which does away tedious get_new, I would like Base::grow to determine what type to create based on type of calling object. I've considered using decltype, but without success.

Code snippet related to attempt to determine type at run-time:

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

DynamicBase above is always determined to be Base, even when this is pointer to Derived

What you want is impossible: you need at least one virtual function call, ie a virtual method overridden in every derived. Consider, for example, the situation that the derived class is defined in another compilation unit. How shall the code for the base class obtain a new derived object of unknown type if not using polymorphism?

Yesterday I came across the Curiously Recurring Template Pattern (crtp) for the first time and I'm fairly sure that it can be used to such that get_new is only defined once.

The idea of crtp is well explained here: https://katyscode.wordpress.com/2013/08/22/c-polymorphic-cloning-and-the-crtp-curiously-recurring-template-pattern/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM