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