// Purpose.  Prototype design pattern based non-invasive customization demo.
// 
// Steps:
// o Add a dictionary (array) of prototypical instances to the base class.
// o The dictionary is of type "Base*"
// o Add an addPrototype() member function to the base class
// o Add a type_ data member and getType() member function to the base class
// o Add a findAndClone() member function to the base class
// o Add a clone() pure virtual function to the base class
// o Each "Derived" class has a private static data member of type "Derived"
// o When this static data member is initiailized, it will call the "1-arg" ctor
// o The "1-arg" ctor calls addPrototype( this )
// o The inherited clone() member does "new Derived"
// o main() calls Base::findAndClone( "Derived" ) to request instances

#include 
#include 

class Base {
public:
   virtual void doIt() = 0;
   static Base* findAndClone( char* type ) {
      for (int i=0; i < totalPrototypes_; i++)
         if ( ! strcmp( type, prototypes_[i]->getType()))
            return prototypes_[i]->clone();
      return 0; }
protected:
   void addPrototype( Base* proto ) {
      prototypes_[totalPrototypes_++] = proto; }
   char          type_[10];
private:
   char*         getType() { return type_; }
   virtual Base* clone() = 0;
   static Base*  prototypes_[10];
   static int    totalPrototypes_;
};
Base* Base::prototypes_[];
int   Base::totalPrototypes_ = 0;

main( int argc, char* argv[] )
{
   Base**  objects;
   objects = new Base*[ argc-1 ];
   for (int i=1; i < argc; i++)
      objects[i-1] = Base::findAndClone( argv[i] );
   for (i=0; i < argc-1; i++)
      if (objects[i]) objects[i]->doIt();
   for (i=0; i < argc-1; i++)
      delete objects[i];
}

class Derived : public Base {
public:
   /* virtual */ void  doIt()  { cout << "Derived: doIt" << endl; }
private:
   Derived() { strcpy( type_, "Derived" ); }
   Derived( int ) {
      strcpy( type_, "Derived" );
      addPrototype( this ); }
   /* virtual */ Base* clone() { return new Derived; }
   static Derived addPrototype_;
};
Derived Derived::addPrototype_( 1 );

class Subclass : public Base {
public:
   /* virtual */ void  doIt()  { cout << "Subclass: doIt" << endl; }
private:
   Subclass() { strcpy( type_, "Subclass" ); }
   Subclass( int ) {
      strcpy( type_, "Subclass" );
      addPrototype( this ); }
   /* virtual */ Base* clone() { return new Subclass; }
   static Subclass addPrototype_;
};
Subclass Subclass::addPrototype_( 1 );

// countach > proto_simple b Subclass Derived Derived a
// Subclass: doIt
// Derived: doIt
// Derived: doIt