#include <iostream>
#include <vector>
#include <memory>

struct PBaseVisitor;

struct PBase {
  virtual int get_id() { return 0; }
  virtual void accept(PBaseVisitor &v);
};
struct P1 : PBase {
  int get_id() override { return 1; }
  void accept(PBaseVisitor &v) override;
};
struct P2 : PBase {
  int get_id() override { return 2; }
  void accept(PBaseVisitor &v) override;
};

class SBase {
public:
  virtual ~SBase() {}
  void doIt(PBase &p) { this->internalDoIt(p); }

private:
  virtual void internalDoIt(PBase &p) = 0;
};

struct PBaseVisitor {
  virtual ~PBaseVisitor() {}
  virtual void visit(PBase &p) = 0;
  virtual void visit(P1 &p) { visit(static_cast<PBase &>(p)); };
  virtual void visit(P2 &p) { visit(static_cast<PBase &>(p)); };
};

void PBase::accept(PBaseVisitor &v) { v.visit(*this); }
void P1::accept(PBaseVisitor &v)    { v.visit(*this); }
void P2::accept(PBaseVisitor &v)    { v.visit(*this); }

class S : public SBase {
  struct doItImpl : PBaseVisitor {
    doItImpl(S *s) : s(s) {}
    S *s;
    virtual void visit(PBase &p) { s->internalDoItImpl(p); };
    void visit(P1 &p) override   { s->internalDoItImpl(p); };
    void visit(P2 &p) override   { s->internalDoItImpl(p); };
  };
  virtual void internalDoIt(PBase &p) {
    doItImpl impl(this);
    p.accept(impl);
  }
  void internalDoItImpl(PBase &p) { std::cout << "PBase: " << p.get_id() << '\n'; }
  void internalDoItImpl(P1 &p)    { std::cout << "P1: " << p.get_id() << '\n'; }
  void internalDoItImpl(P2 &p)    { std::cout << "P2: " << p.get_id() << '\n'; }
};

int main() {
  std::vector<std::unique_ptr<PBase> > vec;
  vec.emplace_back(new PBase);
  vec.emplace_back(new P1);
  vec.emplace_back(new P2);

  S s;
  SBase &bref = s; // Angenommn, dass du von irgendwo her einen
                   // Basisklassen-Zeiger/Referenz hast..

  for (auto &p : vec)
    bref.doIt(*p);
}