c++listclasspolymorphismderived

Appending to polymorphic list in C++?


I am new to C++ and trying to make list polymorphic/accepting anything deriving from a base class. The issue is that this list must be private, using separate methods to append and interrogate it.

After some research, I was able to get close in a safe manner through smart pointers.

Here is what I have arrived at:

class Shape
{
public:
    Shape(std::string name)
    {
        this->name = name;
    }

    std::string name;
    std::string getName(void)
    {
        return this->name;
    }
};

class ShapeCollector
{
public:
    void addShape(Shape shape)
    {
        this->shapes.push_back(std::make_unique<Shape>("hey"));
    }

private:
    std::vector <std::unique_ptr<Shape>> shapes;
};

I would like to be able to replace the make_unique call with the shape parameter, however nothing I try seems to play correctly.

I could create each derived class inside ShapeCollector, mirroring the constructor arguments as parameters, but this feels very counter intuitive.

Any help would be appreciated!


Solution

  • Write addShape to take the derived class as a template parameter:

    template<class Derived, class... Args>
    void addShape(Args&&... args) {
        // std::forward will correctly choose when to copy or move
        std::unique_ptr<Shape> shape (new Derived(std::forward<Args>(args)...));
        shapes.push_back(std::move(shape)); 
    }
    

    This will allow you to give addShape the arguments for the derived classs constructor. For example, if we have aCircle` class:

    class Circle : public Shape {
        double radius;
        double x;
        double y;
       public:
        Circle(double radius, double x, double y) 
          : Shape("circle"), radius(radius), x(x), y(y) 
        {}
    };
    

    Adding it is simple:

    ShapeCollector shapes;
    shapes.addShape<Circle>(10.0, 0.0, 0.0);