Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

Lethe

C++ Problem (Advanced)

This topic is 5784 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a ''simple'' problem - but I can''t find an elegent answer. The problem is that I want to convert a class''s name - as a null terminated string - into a pointer to a newly declared version of this class. (The constructor never takes parameters.) So for example I want to get to get from "DList" to void * ptr = new DList(). And then theres the nasty bit - the list of classes that it suports has to be extensible at any point in the code - a switch statement is not acceptable. Calling a macro with the class name after each class you want in the list it will convert or similer is what I''m after. So far I have one solution - it involves templates, closures, namespaces and a long macro, with a singlton to keep it all company. I''m not even entirelly sure it would work, not to mention how compiler dependent it would be. Any nice friendly solutions coders? -Lethe

Share this post


Link to post
Share on other sites
Advertisement
Could you post an example usage of the code? Are you trying to get something so that the user can enter a class name into a null terminated string and then create an instance of the class that the user named?

Share this post


Link to post
Share on other sites
Object Factories. If you don''t have Modern C++ Design, now is the time to make a smart purchase!

Otherwise, I''m sure somebody here can explain it to you (or you can Google it), but I don''t have the time. Sorry.

Share this post


Link to post
Share on other sites
This is the (Abstract) Factory pattern. Basically, you have
a "factory" class that can produce one of many classes that
are "registered" to its database. Do more research on
it as it is non-trivial. And yes, the factory is usually
a Singleton.

Some books that may help are Design Pattern and Modern C++ Design.



Kami no Itte ga ore ni zettai naru!

Share this post


Link to post
Share on other sites
That singlton I mentioned in my list of insane features is effectivly an object factory - a sort of dynamic one - in reality it would be a dictionary that converts strings to new versions of an associated object. The problem is not maintaining that - I've used & created them before - the problem is how to add objects to it.

I want to be able to declare at *any point* in my code a class, then add it to my 'object factory' there and then - no going back to edit the object factory or adding the object to some list in some peice of code. The factory won't be in the same object file afterall.

Then at any point in the code - before or after - I would want to write

    
void * ptr = MakeClass("BClass");


Thanks all for your input so far.
-Lethe

[edited by - Lethe on July 26, 2002 5:03:04 PM]

Share this post


Link to post
Share on other sites
You need an object that does the registration for you.

Read this. There is a full implementation :

http://www.cuj.com/experts/1906/hyslop.htm

Share this post


Link to post
Share on other sites
Just read that link - that solution happens to be rather close to what I was planning to do - and if you read it you might see why I don''t want to do it! Especially as I have even more functionality required so it will get even friendlier still;-) I was hoping for a more elegent solution - I suspect by the time someone thinks of one I could have implimented the not so friendly one myself. Supose I better start...

Useful link however - it gave me some improvments over my original idea - thanks!
-Lethe

Share this post


Link to post
Share on other sites
Not sure if this will be much use to you but here is one way to do it (this is roughly how the Half-Life engine handles it)


          
//This should be used outside of any functions preferably in the

// same file (note there will need to be a slight difference

//between the class name and the string for this to work (for

// example remove the C from the front of it

#define REGISTER_CLASS(classname,stringname) __declspec(dllexport) void* stringname(){void *c = new classname; return c;
}

typedef void *(*GET_CLASS)();

void *CreateClass(LPSTR Name)
{
//There should be a variable hInstance (containing the instance of the program you are running now)

GET_CLASS *Function = (GET_CLASS*)GetProcAddress(hInstance,Name);
if(Function == NULL)
{
return NULL;
//error

}
void *rv = Function();
return rv;
}

//example

class CClass
{
public:
void hello() {};
};

//then in a .cpp file

REGISTER_CLASS(CCLass,Class)

//to create this class you would call

something = CreateClass("Class");


like i said dunno if this will be useful. I just wrote that code there, so there will probably be bugs in it (and it's very messy) and even the entire context might not work. anyway just a quickly put together suggestion so if you don't like the look of it feel free to ignore it

EDIT : Fixed a few mistakes in the code above
[edited by - Grambo on July 26, 2002 5:57:03 PM]

[edited by - Grambo on July 26, 2002 6:00:00 PM]

[edited by - Grambo on July 26, 2002 6:01:16 PM]

[edited by - Grambo on July 26, 2002 6:44:53 PM]

Share this post


Link to post
Share on other sites
Just a quick idea: if what you're worrying about is writing a new function for each object, you could use templated functors to 'automate' that job, and store functors instead of pointers to functions in the factory:

  template<class T>
struct CreateObject{
string name;
CreateObject(string newname):name(newname){}
T *Create(){return new T;}
};

template<class T>
void Factory::RegisterClass(string name){
ObjectCreatorList.push_back(CreateObject<T>(name));
}


You get the idea... It simplifies the client code somewhat.

Cédric

EDIT: Glanced at the CUJ article (or novel); it might be the same idea, but I'm too lazy to check it out.

[edited by - cedricl on July 26, 2002 6:04:07 PM]

[edited by - cedricl on July 26, 2002 6:04:40 PM]

Share this post


Link to post
Share on other sites
Here ya go... the macro and implementation are ugly, but the use in your code looks nice. You could also wrap up the creation of an instance of a class into another macro, but that's up to you.


    
#include "stdafx.h"
#include <map>

class BaseFactory
{
public:
BaseFactory()
{
m_mapDb.insert(std::pair<char*, BaseFactory*>("BaseFactory", this));
}

static void *CreateInstance(char *pClassName)
{
std::map<char*, BaseFactory*>::iterator it = m_mapDb.find(pClassName);
BaseFactory *pFact = it->second;
if(pFact == NULL)
return NULL;

return pFact->CreateNew();
}

protected:
virtual void *CreateNew()
{
return NULL;
}

static std::map<char *, BaseFactory *> m_mapDb;
};
std::map<char*, BaseFactory*> BaseFactory::m_mapDb = std::map<char*, BaseFactory*>();
BaseFactory _Factory;

#define DEFINE_FACTORY( c )
class c##Factory : public BaseFactory { public: c##Factory() { m_mapDb.insert(std::pair<char*, BaseFactory*>(#c, this)); } protected: void *CreateNew() { return new c(); } }; c##Factory _Factory##c;

#define CREATE_INSTANCE( c )(c##*)BaseFactory::CreateInstance(#c);


class a
{
public:
void PrintType()
{
printf("a\n");
}
};
DEFINE_FACTORY(a);

class b
{
public:
void PrintType()
{
printf("b\n");
}
};
DEFINE_FACTORY(b);

int _tmain(int argc, _TCHAR* argv[])
{
a *pA = (a *)BaseFactory::CreateInstance("a");
void *pV = BaseFactory::CreateInstance("b");

pA->PrintType();
((b*)pV)->PrintType();
return 0;
}




[edited by - jonstelly on July 26, 2002 6:39:36 PM]

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!