|
Boost : |
Subject: [boost] Re : typeof or similar
From: Pierre Morcello (pmorcell-cppfrance_at_[hidden])
Date: 2010-02-23 16:17:31
Hello,
Steffen Roeber wrote :
>>>My preferred way would be something like a factory:
>>>> [...]
>>>>>Base *derived = Factory::createDerived<sameAsBase> (base);
I am not convinced you are on the good mailing list ?
Anyway, I think I can give you that. I wrote it for you ^^.
First the .h, then an example of use.
////////////////////
////////////////////.H
////////////////////
#include <map>
#include <boost/shared_ptr.hpp>
#include <memory>
#define nullptr NULL;
typedef int SomeClassId;
// Wichtig : you will need to specialise extractId for each of your template types.
// make sure to send a different id for each class.
template <class T>
struct ExtractId
{
static SomeClassId extractTypeId()
{
return -1;
}
};
// I retake your example
class Base
{
public:
virtual ~Base(){}
virtual SomeClassId getTypeId(){throw;}
};
template <class T>
class BaseT : public Base
{
virtual ~BaseT(){}
virtual SomeClassId getTypeId(){return ExtractId<T>::extractTypeId();}
};
// this was unclear for me if you wanted that Derived derives from Base or not.
// I consider that what you wrote ("Base *derived = base->createDerived(); //base is a Base *")
// implies that Derived inherits from Base after all.
template <class T>
class Derived : public Base
{
virtual ~Derived(){}
virtual SomeClassId getTypeId(){return ExtractId<T>::extractTypeId();}
};
// a base factory class, needed for polymorphism.
class OneTypeFactory
{
public:
virtual ~OneTypeFactory(){}
virtual Base* createDerived(){throw;}
virtual SomeClassId getTypeId(){throw;}
};
template <class T>
class InheritedFactory : public OneTypeFactory
{
public:
virtual ~InheritedFactory(){}
virtual Base* createDerived(){ return new Derived<T>();}
virtual SomeClassId getTypeId(){ return ExtractId<T>::extractTypeId();}
};
class AllFactories
{
public:
// you can make it some singleton if you want... (e.g static std::auto_ptr<AllFactories> sData;)
AllFactories():mAllFactories(){}
// to register the factories => insert them in the mAllFactories.
void registerFactory(boost::shared_ptr<OneTypeFactory> pFactory)
{
mAllFactories.insert(std::make_pair(pFactory->getTypeId(), pFactory));
}
// create a derived from b, using the same template type.
Base* createDerived(Base* pBase)
{
Base* lResult = nullptr;
if(pBase)
{
lResult = createDerived(pBase->getTypeId());
}
return lResult;
}
private:
Base* createDerived(SomeClassId pId)
{
Base* lResult = nullptr;
// if found in mAllFactories, ask the corresponding factory to create
// the derived...
TFactories::iterator lFound = mAllFactories.find(pId);
if(lFound != mAllFactories.end())
{
lResult = (lFound->second)->createDerived();
}
return lResult;
}
typedef std::map<SomeClassId, boost::shared_ptr<OneTypeFactory> > TFactories;
TFactories mAllFactories;
};
// and then, at the beginning of the program, you can register factories for your types.
// and later you can call : AllFactories::getSingleton()->createDerived(base); // base is a Base*
////////////////////
////////////////////example of use in .cpp
////////////////////
#include "factoryforfun.h"
// I write a little macro to help the copy/paste job.
// of course, use typedef or anything (boost.preprocessor sequence) to
// avoid ',' in the macro...
// value, corresponding type.
#define MACRO_WRITEEXTRACTID(X,Y) \
template <> \
struct ExtractId<Y> \
{ \
static SomeClassId extractTypeId() \
{ \
return X; \
} \
};
MACRO_WRITEEXTRACTID(1, int)
MACRO_WRITEEXTRACTID(2, double)
MACRO_WRITEEXTRACTID(3, char)
// its also possible to only register the type with a template
// at the beginning of the program, and make a counter increase,
// etc...
int main(void)
{
// program begins
AllFactories lAllFactories;
lAllFactories.registerFactory(boost::shared_ptr<OneTypeFactory>(new InheritedFactory<int>()));
lAllFactories.registerFactory(boost::shared_ptr<OneTypeFactory>(new InheritedFactory<double>()));
lAllFactories.registerFactory(boost::shared_ptr<OneTypeFactory>(new InheritedFactory<char>()));
// later...
// I create my pointers
std::auto_ptr<Base> lBaseT_Char (new BaseT<char>() );
std::auto_ptr<Base> lBaseT_Double (new BaseT<double>());
std::auto_ptr<Base> lBaseT_Int (new BaseT<int>() );
// I create the derived
std::auto_ptr<Base> lShouldBeDerived_Char;
std::auto_ptr<Base> lShouldBeDerived_Double;
std::auto_ptr<Base> lShouldBeDerived_Int;
if(true)
{
//pseudo - dynamic branching creation.
lShouldBeDerived_Char = std::auto_ptr<Base>(lAllFactories.createDerived(lBaseT_Char.get()));
lShouldBeDerived_Double = std::auto_ptr<Base>(lAllFactories.createDerived(lBaseT_Double.get()));
lShouldBeDerived_Int = std::auto_ptr<Base>(lAllFactories.createDerived(lBaseT_Int.get()));
}
// works like a charm : they are all of the good type.
////////////////////
////////////////////end.
////////////////////
Hope you like it ?
Best regards,
Pierre Morcello
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk