
Hi, I have 3 classes: 1. class Base { public: virtual Base *createDerived() { return 0; } }; 2. template <class T> class BaseT : public Base { public: virtual Base *createDerived() { return new DerivedT<T>(); //nicht smart, because DerivedT must be known } }; 3. template <class T> class DerivedT : public BaseT<T> { }; So far so good. Or not. But now the problems are starting. Base *base = new BaseT<int>; This object it created at a place that is not known where I want to create: Base *derived = base->createDerived(); //base is a Base * The result is an object that has the same template type as 'base'. Finally I got my desired result, but the problem is the relation downward relation between BaseT and DerivedT. My preferred way would be something like a factory: class Factory { public: template <class T> static Base *createDerived<T>() { return new DerivedT<T>(); } }; But how can I tell the factory which type to be used. Base *derived = Factory::createDerived<sameAsBase> (base); //base is a Base * I think there is no "normal" C++ language support. But Boost has some methods that by-pass some language constraints. I took a loot at something like 'typeof'. But I don't get the things together. Has anybody any idea? Or is it impossible to do this? Kind regards Steffen

Steffen Roeber wrote:
My preferred way would be something like a factory:
class Factory
{
public:
template <class T>
static Base *createDerived<T>()
{
return new DerivedT<T>();
}
};
But how can I tell the factory which type to be used.
Base *derived = Factory::createDerived<sameAsBase> (base); //base is a Base *
You can't, since you lost that information. Even if you stored a type identifier for T, you couldn't get the type out of it, all you can do is call a function depending on that type identifier.
But Boost has some methods that by-pass some language constraints. I took a loot at something like 'typeof'.
typeof gives the static type of an object has deduced by the compiler, not the dynamic type. So it's useless in your case.

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

Steffen Roeber wrote:
My preferred way would be something like a factory:
...
I think there is no "normal" C++ language support. But Boost has some methods that by-pass some language constraints. I took a loot at something like 'typeof'. But I don't get the things together.
The trunk version of Boost provides a ready-made factory as a function object. It can be assigned to a Boost.Function with an appropriate signature if you need an opaque, polymorphic handle. E.g: #include <boost/functional/factory.hpp> #include <boost/function.hpp> #include <map> typedef boost::function< an_abstract_class*() > a_factory; // [...] int main() { std::map<std::string,a_factory> factories; factories["a_name"] = boost::factory<a_concrete_class*>(); factories["another_name"] = boost::factory<another_concrete_class*>(); // [...] an_abstract_class* something = factories["a_name"](); // [...] } Regards, Tobias
participants (4)
-
Mathias Gaunard
-
Pierre Morcello
-
Steffen Roeber
-
Tobias Schwinger