So, I've got a pluggable factory that can construct objects within a given heirarchy, but I have an issue with initialising derived objects within this heirarchy. Here's the source code for my factory class
// Factory.h
#ifndef FACTORY_H
#define FACTORY_H
#include <map>
#include "ObjectTypes.h"
template <typename BASE_TYPE>
class Factory
{
typedef std::map<OBJ_TYPE,Factory*> FactoryRegistry;
static FactoryRegistry& Registry();
virtual BASE_TYPE* Create() const = 0;
public:
Factory(OBJ_TYPE type);
static BASE_TYPE* Construct(OBJ_TYPE type);
};
template <typename BASE_TYPE>
Factory<BASE_TYPE>::Factory(OBJ_TYPE type)
{
Registry().insert(std::make_pair(type,this));
}
template <typename BASE_TYPE>
typename Factory<BASE_TYPE>::FactoryRegistry& Factory<BASE_TYPE>::Registry()
{
static Factory<BASE_TYPE>::FactoryRegistry m_registry;
return m_registry;
}
template <typename BASE_TYPE>
BASE_TYPE* Factory<BASE_TYPE>::Construct(OBJ_TYPE type)
{
Factory<BASE_TYPE>::FactoryRegistry::iterator iter = Registry().find(type);
if (iter != Registry().end())
{
Factory<BASE_TYPE>* pDerivedFactory = iter->second;
return pDerivedFactory->Create();
}
else
return NULL;
}
#endif
and here's an object and its factory...
// AnObject.h
#ifndef ANOBJECT_H
#define ANOBJECT_H
#include "Factory.h"
#include "BaseTypes.h"
class AnObject : public BaseObject
{
int x,y;
public:
AnObject():BaseObject(BaseObject::NextValidID()){
SetType(TYPE_1);
}
void Initialise(int a, int b){x=a;y=b;}
};
class AnObjectFactory : public Factory<BaseObject>
{
public:
AnObjectFactory():Factory<BaseObject>(TYPE_1){}
private:
BaseObject* Create() const;
static const AnObjectFactory register_this;
};
#endif
// AnObject.cpp
#include "AnObject.h"
#include <iostream>
const AnObjectFactory AnObjectFactory::register_this;
BaseObject* AnObjectFactory::Create() const
{
AnObject* l_pObj = NULL;
try
{
l_pObj = new AnObject;
}
catch(std::bad_alloc& ba)
{
std::cout << ba.what() << std::endl;
}
return l_pObj;
}
and another object and factory
// AnotherObject.h
#ifndef ANOTHEROBJECT_H
#define ANOTHEROBJECT_H
#include "Factory.h"
#include "BaseTypes.h"
class AnotherObject : public BaseObject
{
float x,y,z;
public:
AnotherObject():BaseObject(BaseObject::NextValidID()){
SetType(TYPE_2);
}
void Initialise(float a, float b, float c){x=a;y=b;z=c;}
};
class AnotherObjectFactory : public Factory<BaseObject>
{
public:
AnotherObjectFactory():Factory<BaseObject>(TYPE_2){}
private:
BaseObject* Create() const;
static const AnotherObjectFactory register_this;
};
#endif
#include "AnotherObject.h"
#include <iostream>
const AnotherObjectFactory AnotherObjectFactory::register_this;
BaseObject* AnotherObjectFactory::Create() const
{
AnotherObject* l_pObj = NULL;
try
{
l_pObj = new AnotherObject;
}
catch(std::bad_alloc& ba)
{
std::cout << ba.what() << std::endl;
}
return l_pObj;
}
Here's the base type from which these types are derived...
// BaseTypes.h
#ifndef BASETYPES_H
#define BASETYPES_H
#include "ObjectTypes.h"
typedef unsigned int ID_TYPE;
class BaseObject
{
ID_TYPE m_uID;
OBJ_TYPE m_eType;
static ID_TYPE m_uNextValidID;
void SetID(ID_TYPE l_uID);
protected:
void SetType(OBJ_TYPE type);
public:
BaseObject(ID_TYPE l_uID);
static ID_TYPE NextValidID();
ID_TYPE ID(){ return m_uID; }
OBJ_TYPE TYPE(){ return m_eType; }
};
#endif
#include "BaseTypes.h"
ID_TYPE BaseObject::m_uNextValidID = 0;
BaseObject::BaseObject(ID_TYPE l_uID)
{
SetType(TYPE_DEFAULT);
SetID(l_uID);
}
void BaseObject::SetType(OBJ_TYPE type)
{
m_eType = type;
}
void BaseObject::SetID(ID_TYPE l_uID)
{
m_uID = l_uID;
m_uNextValidID++;
}
ID_TYPE BaseObject::NextValidID(void){
return m_uNextValidID;
}
and finally an enumeration for identifying types...
// ObjectTypes.h
#ifndef OBJECTTYPES_H
#define OBJECTTYPES_H
enum OBJ_TYPE {TYPE_DEFAULT=0,TYPE_1, TYPE_2};
#endif
So, here is some sample usage...
// main.cpp
#include <iostream>
#include "Factory.h"
#include "AnObject.h"
#include "AnotherObject.h"
int main(void)
{
BaseObject* pObj1 = Factory<BaseObject>::Construct(TYPE_1);
BaseObject* pObj2 = Factory<BaseObject>::Construct(TYPE_2);
AnObject* pAnObj1 = reinterpret_cast<AnObject*>(pObj1);
pAnObj1->Initialise(1,2);
std::cout << pObj1->TYPE() << ": " << pObj1->ID() << std::endl;
std::cout << pObj2->TYPE() << ": " << pObj2->ID() << std::endl;
return 0;
}
Now, the issue I have with this framework is having to use reinterpret_cast<>() to gain access to the Initialise member function of each type. Obviously, if the function signature of the initialisation routine of each derived class was the same, I could provide an abstract interface through the base class... but given that derived classes are expected to have different initialisation requirements and different initialisation lists, how can I get around this? I don't want to have to know the class type beyong the enumeration list... and I'd like to avoid using the 'ellipsis' construct.
Any ideas about how I could change this framework to solve this problem? Are there standard solutions out (I've looked but couldn't find any).
Thanks,
Timkin