Generic Class Factory – C++ Part 2 / 4

This 2nd post in the generic class factory series focuses on creating objects of different types in C++, which I have not seen published before.  This means that just one generic class factory can create objects that have no common base class – which will save on code and complexity when having to deal with many different base class objects that need to be created.

The first post in the series introduced a generic class factory that can only work to create objects of the same base class, when a class factory should be used instead of simply creating an object, and how a generic class factory works.

This is the last post in the series for C++.  The last two posts will deal with C# generic class factories.

A  C++ Generic Class To Create Unrelated Objects

template <class TKey>
class GenericFactories
{
   // This class implements a generic factory that can be used to create any type.
   typedef void* (*CreateObjFn)(vector<void*> &args); // Defines the CreateObjFn function pointer that points to the object creation function.
   typedef tr1::unordered_map<TKey, CreateObjFn> FactoryMap; // Hash table to map the key to the function used to create the object.
public:
   void Register(const TKey &keyName, CreateObjFn pCreateFn)
   {
      // Store the object type name in the hash table.
      FactMap[keyName] = pCreateFn;
   }

   template <class TType>
   TType* CreateObj(const TKey &keyName, vector<void*> &args)
   {
      // This method looks for the name in the hash map.  If it is not found, then an exception is thrown.
      // If it is found, then it creates the specified object returns a pointer to it.
      //
      FactoryMap::iterator It = FactMap.find(keyName);
      if (It != FactMap.end())
      {
         void* pObj = It->second(args); // Call the method to create the object.
         TType* Obj = static_cast<TType*>(pObj); // Cast the object to the specified type.
         return Obj;
      }
      throw "GenericFactories::CreateObj: key was not found in hashtable.  Did you forget to register it?";
   }
private:
   FactoryMap FactMap;
};

TKey is the only class parameter, which is used as the type of key.  This is used to keep track of the type of object to be created.  The typedef:

typedef void* (*CreateObjFn)(vector<void*> &args);

is subtlety different from the typedef in the first generic class factory described in the first post.  It now returns a void pointer instead of the base class parameter type.  This is one of the insights required to make it work with unrelated types.  But, this also means that the static creation methods used to create the object must be defined to return a null pointer.  As in the first post, the user is required to create the static creation method to create the object.

The Register method must be called prior to calling CreateObj so that the generic factory knows which method to call to create the object.  As in the first post, a hashtable is used to keep track of the key and the static creation method.

The new CreateObj method introduces a new function template parameter, which is called TType.  By moving the class template parameter out of the class definition to a function template parameter in the CreateObj method means that the class is no longer constrained to creating objects of a specific base class.  Any type of class can now be created by this factory – even classes with very different base types.

When creating the object, the base class family must be supplied to CreateObj as the function template parameter in order for the correct type to be returned.  A static_cast is done to convert the void pointer returned by the static creation object method to the expected type.

The following code shows how to use this generic factory:

GenericFactories<int> GenFacts; // Create a generic class factory that works with int keys.
GenFacts.Register(1, &RedColor::CreateObj); // Register 1 to create a red color object.
GenFacts.Register(100, &Dog::CreateObj); // Register 100 to create a dog object.
// Prepare the arguments needed to create a red object with a hue of 15.
vector<void*> Args;
Args.push_back("Light Red");
int Hue = 15;
Args.push_back(&Hue);
// Create a red color object from the factory.
unique_ptr<Color> pRedColor(GenFacts.CreateObj<Color>(1, Args));
cout << "Color object is of type " << pRedColor->GetType() << endl;
// Now create a completely different object from the factory - a dog animal object.
Args[0] = "Max";
int YearsOld = 4;
Args[1] = &YearsOld;
unique_ptr<Animal> pDoggy(GenFacts.CreateObj<Animal>(100, Args));
cout << "Animal object is of type " << pDoggy->GetType() << endl;

The code for this class may be downloaded by following this link.

Advertisements

About Bob Bryan

Software developer for over 20 years. Interested in efficient software methodology, user requirements, design, implementation, and testing. Experienced with C#, WPF, C++ , VB, Sql Server, stored procedures, and office tools. MCSD.
This entry was posted in C/C++, software development and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s