#include <cstdio>

// External implementation 1
class SomeShape {};
class SomeBody { public: SomeShape *shape; };

// External implementation 2
class OtherShape {};
class OtherBody { public: OtherShape *shape; };

//////////////

class Shape
{
public:
  virtual const char *name() { return "Shape"; }
};


template<class Shape>
class Body 
{
  Shape *shape; 	
public:
  void setShape(Shape *s) { 
  	shape=s; 
    printf("Setting shape: %s\n", s->name());
  }
};

template <class Shape, class Body>
class Factory
{
public:
  Shape *makeShape()
    { return new Shape(); }
  Body *makeBody()
    { return new Body(); }
};

//////////////

class AShape : public Shape
{
public:
  SomeShape *someShape;
  virtual const char *name() { return "AShape"; }
};

class ABody : public Body<AShape>
{
protected:
  SomeBody *someBody;
public:
  ABody() { someBody = new SomeBody; }
};


//////////////

class BShape : public Shape
{
public:
  OtherShape *otherShape;
  virtual const char *name() { return "BShape"; }
};

class BBody : public Body<BShape>
{
protected:
  OtherBody *otherBody;
public:
  BBody() { otherBody = new OtherBody; }
};

using BFactory = Factory<BShape, BBody>; 
using AFactory = Factory<AShape, ABody>; 

int main()
{
  // Of course in a real program we would return
  // a particular Factory from some selection function,
  // this should ideally be the only place the user is
  // exposed to the implementation selection.
  AFactory f1;
  BFactory f2;

  // Associate a shape and body in implementation 1
  auto *s1 = f1.makeShape();
  auto *b1 = f1.makeBody();
  b1->setShape(s1);

  // Associate a shape and body in implementation 2
  auto *s2 = f2.makeShape();
  auto *b2 = f2.makeBody();
  b2->setShape(s2);

  // This should not be possible, compiler error ideally
  //b2->setShape(s1);

  return 0;
}