Overview
Examples
Screenshots
Comparisons
Applications
Download
Documentation
Tutorials
Bazaar
Status & Roadmap
FAQ
Authors & License
Forums
Funding Ultimate++
Search on this site
Search in forums












SourceForge.net Logo
Home » Developing U++ » U++ Developers corner » Template class factory
Template class factory [message #24382] Wed, 13 January 2010 11:17 Go to next message
mdelfede is currently offline  mdelfede
Messages: 1307
Registered: September 2007
Ultimate Contributor
Having the need to create some class instances at runtime by class name (String, not type), I developed a small templatized class factory; it's the first step for the polymorphic xmlizer that I'll publish when ready.

Thank to Mirek who helped me with templates ! Smile

ClassFactory.h
#ifndef _ClassFactory_ClassFactory_h_
#define _ClassFactory_ClassFactory_h_

#include <Core/Core.h>
using namespace Upp;

template<class T> class WithFactory
{
	private:
		typedef One<T> (*CreateFunc)();
		typedef VectorMap<String, CreateFunc>mapType;
		static mapType &classMap() { static mapType cMap; return cMap; }
		template<class D> static One<T> __Create(void) { return One<T>((T *)new D); }
	public:
	
		template<class D> static void Register(const String &name) { classMap().Add(name, __Create<D>); }
		static One<T> Create(const String &className) { return classMap().Get(className)(); }
		static Vector<String> const &Classes(void) { return classMap().GetKeys(); }
};

#define REGISTERCLASS(type) \
	INITBLOCK { \
	type::Register<type>(#type); \
}
#endif


Sample usage:

#include "ClassFactory.h"

class Base : public WithFactory<Base>
{
	public:
		virtual String WhoAmI(void) { return "Base"; }
};

class Derived : public Base
{
	public:
		virtual String WhoAmI(void) { return "Derived"; }
};

REGISTERCLASS(Base);
REGISTERCLASS(Derived);

CONSOLE_APP_MAIN
{
	One<Base> p1 = Base::Create("Base");
	One<Base> p2 = Base::Create("Derived");
	
	Cerr() << "p1 is a '" << p1->WhoAmI() << "'\n";
	Cerr() << "p2 is a '" << p2->WhoAmI() << "'\n";
	
}


output :

p1 is a 'Base'
p2 is a 'Derived'


Ciao

Max
Re: Template class factory [message #24383 is a reply to message #24382] Wed, 13 January 2010 11:40 Go to previous messageGo to next message
mdelfede is currently offline  mdelfede
Messages: 1307
Registered: September 2007
Ultimate Contributor
A better version with RTTI class identification :

#ifndef _ClassFactory_ClassFactory_h_
#define _ClassFactory_ClassFactory_h_

#include <Core/Core.h>
using namespace Upp;

template<class T> class WithFactory
{
	private:
		typedef One<T> (*CreateFunc)();
		typedef VectorMap<String, CreateFunc>mapType;
		static mapType &classMap() { static mapType cMap; return cMap; }
		template<class D> static One<T> __Create(void) { return One<T>((T *)new D); }
		String myType;
	public:
	
		template<class D> static void Register(const String &name) { classMap().Add(name, __Create<D>); }
		static One<T> Create(const String &className)
		{
			One<T> me = classMap().Get(className)();
			me->myType = className;
			return me;
		}
		static Vector<String> const &Classes(void) { return classMap().GetKeys(); }
		String const &IsA(void) { return myType; }
};

#define REGISTERCLASS(type) \
	INITBLOCK { \
	type::Register<type>(#type); \
}
#endif


Usage :

#include "ClassFactory.h"

class Base : public WithFactory<Base>
{
};

class Derived : public Base
{
};

REGISTERCLASS(Base);
REGISTERCLASS(Derived);

CONSOLE_APP_MAIN
{
	One<Base> p1 = Base::Create("Base");
	One<Base> p2 = Base::Create("Derived");

	Cerr() << "p1 is a '" << p1->IsA() << "'\n";
	Cerr() << "p2 is a '" << p2->IsA() << "'\n";
	
}


Now classes knows themselves Smile

Ciao

Max

[Updated on: Wed, 13 January 2010 12:22]

Report message to a moderator

Re: Template class factory [message #24386 is a reply to message #24383] Wed, 13 January 2010 14:08 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Adds 16 bytes per instance (sizeof(String)). Sometimes that is not a good tradeoff.

Could be solved by mapping typeid.

Mirek

[Updated on: Wed, 13 January 2010 14:09]

Report message to a moderator

Re: Template class factory [message #24388 is a reply to message #24386] Wed, 13 January 2010 15:13 Go to previous messageGo to next message
mdelfede is currently offline  mdelfede
Messages: 1307
Registered: September 2007
Ultimate Contributor
Already tried, doesn't work....

String const &IsA(void) { Cerr() << "\n" << typeid(*this).name() << "\n"; return myType; }


prints
11WithFactoryI4BaseE

which has nothing to do with real type.
What I could do is to store just the char*, it should be static data.

Max
Re: Template class factory [message #24389 is a reply to message #24388] Wed, 13 January 2010 15:15 Go to previous messageGo to next message
mdelfede is currently offline  mdelfede
Messages: 1307
Registered: September 2007
Ultimate Contributor
And if I do

String const &IsA(void) { T * p = (T *)this; Cerr() << "\n" << typeid(*p).name() << "\n"; return myType; }


It always output '4Base' even if the class is the derived one.
Compiler bug ?
Re: Template class factory [message #24390 is a reply to message #24389] Wed, 13 January 2010 15:20 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
mdelfede wrote on Wed, 13 January 2010 09:15

And if I do

String const &IsA(void) { T * p = (T *)this; Cerr() << "\n" << typeid(*p).name() << "\n"; return myType; }


It always output '4Base' even if the class is the derived one.
Compiler bug ?



Do you have any virtual function in Base?

Mirek
Re: Template class factory [message #24391 is a reply to message #24390] Wed, 13 January 2010 15:20 Go to previous messageGo to next message
mdelfede is currently offline  mdelfede
Messages: 1307
Registered: September 2007
Ultimate Contributor
Nope ! Is that the problem ???
Re: Template class factory [message #24392 is a reply to message #24391] Wed, 13 January 2010 15:37 Go to previous message
mdelfede is currently offline  mdelfede
Messages: 1307
Registered: September 2007
Ultimate Contributor
Well, quite interesting topic Smile

The definitive factory, thanx to Mirek know-how :

#ifndef _ClassFactory_ClassFactory_h_
#define _ClassFactory_ClassFactory_h_

#include <Core/Core.h>
using namespace Upp;

template<class T> class WithFactory
{
	private:
		typedef One<T> (*CreateFunc)();
		typedef VectorMap<String, CreateFunc>mapType;
		static mapType &classMap() { static mapType cMap; return cMap; }
		static VectorMap<String, String> &typeMap() { static VectorMap<String, String> tMap; return tMap; }
		template<class D> static One<T> __Create(void) { return One<T>((T *)new D); }
	public:
	
		template<class D> static void Register(const String &name)
		{
			classMap().Add(name, __Create<D>);
			typeMap().Add(typeid(D).name(), name);
		}
		static One<T> Create(const String &className) { return classMap().Get(className)(); }
		static T *CreatePtr(String const &className) { return classMap().Get(className)().Detach(); }
		static Vector<String> const &Classes(void) { return classMap().GetKeys(); }
		String const &IsA(void) { return typeMap().Get(typeid(*this).name()); }
		virtual ~WithFactory() {}
};

#define REGISTERCLASS(type) \
	INITBLOCK { \
	type::Register<type>(#type); \
}
#endif


and the sample usage :
#include "ClassFactory.h"

class Base : public WithFactory<Base>
{
};

class Derived : public Base
{
};

REGISTERCLASS(Base);
REGISTERCLASS(Derived);

CONSOLE_APP_MAIN
{
	One<Base> p1 = Base::Create("Base");
	One<Base> p2 = Base::Create("Derived");

	Cerr() << "p1 is a '" << p1->IsA() << "'\n";
	Cerr() << "p2 is a '" << p2->IsA() << "'\n";
	
	Base *ptr = Base::CreatePtr("Derived");
	Cerr() << "ptr  is a '" << ptr->IsA() << "'\n";
	delete ptr;
	
	Base *d = new Derived;
	Cerr() << "d  is a '" << d->IsA() << "'\n";
	delete d;

}
Previous Topic: Helper for internazionalize arrays of literals
Next Topic: Polymorphic XMLizer
Goto Forum:
  


Current Time: Thu Mar 28 14:40:13 CET 2024

Total time taken to generate the page: 0.01513 seconds