#include <iostream>
#include <functional>
#include <vector>
#include <memory>
#include <random>

struct Base
{
    virtual void print() const = 0;
    virtual ~Base() {}
};


struct D1 : public Base { void print() const { std::cout << "D1\n"; } };
struct D2 : public Base { void print() const { std::cout << "D2\n"; } };
struct D3 : public Base { void print() const { std::cout << "D3\n"; } };
struct D4 : public Base { void print() const { std::cout << "D4\n"; } };
struct D5 : public Base { void print() const { std::cout << "D5\n"; } };


template <typename T>
T* new_class()
{
    return new T;
}

typedef std::function<Base*()> creationFunction;

enum class_type { eD1, eD2, eD3, eD4, eD5 };

creationFunction create [] =
{
    new_class<D1>,
    new_class<D2>,
    new_class<D3>,
    new_class<D4>,
    new_class<D5>
};

Base* getClass(class_type type)
{
    return create[type]();
}

int main()
{
    std::mt19937 engine( (std::random_device())() );
    std::uniform_int_distribution<unsigned> ct(eD1, eD5);

    auto rand_class = [&]() { return static_cast<class_type>(ct(engine)); };

    std::vector<std::unique_ptr<Base>> container;
    for (unsigned i = 0; i < 20; ++i)
        container.emplace_back(getClass(rand_class()));

    for (auto & element : container)
        element->print();
}