Skip to main content
GameDev.net gamedev.net
🔒 Locked

class factory question

Started by dodheim Sep 2, 2006 at 5:38 AM 5 replies 1.3k views
Original Post
dodheim
dodheim
How would you pass constructor arguments to a generic (reusable) class factory? So I could do this: class CMyObject { public: CMyObject(const char* name, int age); } CMyObject* pObj = CMyObject::CreateInstance(CLASS_ID, "Uncle Sam", 17); thx, d0d
NotAYakk
NotAYakk
Quote:
How would you pass constructor arguments to a generic (reusable) class factory?


Please clarify. Your example doesn't explain what you want to me.

From your example:

So I could do this:class CMyObject { public: CMyObject(const char* name, int age); }CMyObject* pObj = CMyObject::CreateInstance(CLASS_ID, "Uncle Sam", 17);


All you would need would be:
class CMyObject {  public:    CMyObject(const char*, int age);    static CMyObject* CreateInstance(int unused_class_id, const char* name, int age) {      return new CMyObject(name, age);    }};


But I seriously doubt that is what you want.

Do you want a function that can take any number of arguements, then determine at run time which constructor to call?
dodheim
dodheim
Sorry for the obscure post :\ I'm talking about the factory design pattern. The factory has a Create function which takes a class id and dynamically instanciates the right class.
The problem is, that if you want these classes to have constructor parameters, you'd have to send them through the factory's Create function, which leads to the problem: how would a *generic* object factory let you pass these class specific parameters?

Have a look at this article:
http://www.gamedev.net/reference/articles/article2097.asp
(scroll to "The finishing touches")

There is a solution provided to this exact problem, I'm only curious if you can think of a better one, as it seems to be a bit hacky :]
NotAYakk
NotAYakk
If you have multiple possible signatures to your creation function, you should have multiple Creation factories. Each one with a given signature.

Another possible way is to pass in a list/vector of boost varient types. Then it becomes the job of the creation function to verify that the parameters passed make sense.

Another idea is to have a "struct CircleCreationArgs;" that is serialized or deserialized.

If you are using the object factory for human-typed commands, your creation functions might simply take a list of arguements that are still strings. It then becomes up to the creation function to turn those strings into usable C++ data. Fortunetally, the problem of turning a list of strings into useful parameter data has been looked into heavily, thanks to the "int main(int argc, char** argv)" signature and how you parse command-line options.

What are you using the creation factory for, may I ask? :)
\
dodheim
dodheim
I use it for creating objects like these stuff:

class IEntity { virtual void Grunt() = 0; };
class CMonster : public IEntity { CMonster(const char* name); void Grunt(); };
class CPeasant : public IEntity { CPeasant(const char* name); void Grunt(); };

IEntity::GetFactory().Register(MONSTER_ENTITY);
IEntity::GetFactory().Register(PEASANT_ENTITY);

IEntity* pEntity = IEntity::GetFactory().Create(MONSTER_ENTITY);
pEntity->Grunt();

Only that I want a generic solution. In the end I sticked with the method mentioned in the article and it seems to work well (I changed my mind a little bit :)).
Xgkkp
Xgkkp
I've been using a method from Bruce Eckels thinking in C++ (Free, very good c++ book series, search the net), basically there is a base 'factory' class that each class of yours creates a version of (and each class of yours is derived from the same base class) like so:

class myclass : public baseobject {     // Your class workingspublic:     class Factory : public factoryclass {         baseobject *create ( void ) { return new myclass; }     }};

You then have a 'factoryclass' which contains a map between, say, a string and a pointer to a factoryclassobject, and a way to get a new class from it.
class factoryclass {public:    map<string, factoryclass *> factories;    static baseobject* createobject(const string& id)    {        if(factories.find(id) != factories.end())            return factories[id]->create();        else	    // Handle the error case here (I throw an exception)    }}

You then 'add' the classes to the factory like so:
factoryclass::factories["myclass"]= new myclass::Factory;

Or write an add function inside the factoryclass class.

I did experiment with function pointers, but it seemed awfully hard to make it flexible. I like this method, it is neat.
NotAYakk
NotAYakk
dodheim, there are good reasons to use the factory pattern.

But, can I ask you, why aren't you just using:
IEntity* pEntity = new CMonster();
?

If you know at compile time which object type you are creating, the factory pattern is ... less useful.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.