Casting Conundrum

Started by
7 comments, last by choffstein 18 years, 10 months ago
I have run myself into a hole this time. I was creating an object factory so I could control and log how objects in my game are being created. The object factory is comprised of "FreeLists." FreeLists are template classes that I created to be initialized to create a certain number of the class. Then you call "createInstance()" to get an instance of that class. The FreeLists in the Object Factory all have to have a derivative type from the base type. When I register a class to the factory, I run into a little bit of an issue. Let me show you the line:
registered[className.c_str()] = (FreeList<BC>*)new FreeList<T>(ONCE, className);
registered is defined as:
typedef FreeList<BC> free_list;
typedef std::map<const char*, free_list*, std::less<std::string> > obj_map;
obj_map registered;
So, as you can see, the map requires that all the FreeLists be casted to FreeList<BC>*. Now, everything runs smoothly until there are no more instances in the list, and the list has to create more for itself. Because of the cast, the freelist refills itself with types of the base class instead of the class it was supposed to be creating. I totally understand why this is happening, but I can't figure out a way around it. Does anyone have any ideas? Total ratings++ if anyone can figure this guy out in a clean manner. Thanks a bunch.
Advertisement
Hmmm, that is tough. I would think that if you're using pointers regarding derived classes, that they would sort of be interchangeble, but then again I'm not really sure.
-----------------------------Play Stompy's Revenge! Now!
The issue is that "FreeList<BC>" and "FreeList<DC>" are not technically derived from one another, despite the fact that BC and DC are...so it doesn't quite work, unfortunately...

Anyone know if there is a way for me to store what the class is within the class itself? Maybe with some sort of RTTI stuff?

The only thing I can think of is using some sort of wrapper class that uses an template initialization function, but have everything be stored with void pointers, and somehow store the class so it knows what to create the next time around -- though, I really don't know how I would do that...and it seems pretty gross.

[Edited by - visage on June 18, 2005 12:41:41 AM]
*bump* ;) I am so freakin stuck..
If you need FreeList<A> and FreeList<B> to be related even though FreeList is just a templated class, you could make a base class that FreeList derives from so all the templated versions have something in common and you have use polymorphism.
"Walk not the trodden path, for it has borne it's burden." -John, Flying Monk
My best gues would be to store a DC pointer in your FreeList class and then use templated constructors to assign the correct type of thing to the DC pointer, sort of like:
class FreeList{public:    template <class T>    FreeList(const T value):_object(T) {}private:    DC * _object;};

If not, perhaps you could get some inspiration from this code, slightly modified from the Functor class from Modern C++ Design:
#ifndef FUNCTOR_H#define FUNCTOR_H#include <cassert>#include "SmartPointer.h"class EmptyClass {};template <typename R, typename P1, typename P2, typename P3>class FunctorStorage{public:	FunctorStorage() {}	virtual ~FunctorStorage() {}	virtual R Execute(P1, P2, P3) = 0;};template <typename R>class FunctorStorage<R, EmptyClass, EmptyClass, EmptyClass>{public:	FunctorStorage() {}	virtual ~FunctorStorage() {}	virtual R Execute() = 0;};template <typename R, typename P1>class FunctorStorage<R, P1, EmptyClass, EmptyClass>{public:	FunctorStorage() {}	virtual ~FunctorStorage() {}	virtual R Execute(P1) = 0;};template <typename R, typename P1, typename P2>class FunctorStorage<R, P1, P2, EmptyClass>{public:	FunctorStorage() {}	virtual ~FunctorStorage() {}	virtual R Execute(P1, P2) = 0;};template <typename R, typename P1, typename P2, typename P3, typename F>class FunctionPointer : public FunctorStorage<R, P1, P2, P3>{public:	FunctionPointer(const F & func):_function(func) {}	virtual ~FunctionPointer() {}	R Execute() {return _function();}	R Execute(P1 param1) {return _function(param1);}	R Execute(P1 param1, P2 param2) {return _function(param1, param2);}	R Execute(P1 param1, P2 param2, P3 param3) {return _function(param1, param2, param3);}private:	F _function;};template <typename R, typename P1, typename P2, typename P3, typename F, class O>class MemberPointer : public FunctorStorage<R, P1, P2, P3>{public:	MemberPointer(const O & object, const F & func):_function(func), _object(object) {}	virtual ~MemberPointer() {}	R Execute() {return ((*_object).*_function)();}	R Execute(P1 param1) {return ((*_object).*_function)(param1);}	R Execute(P1 param1, P2 param2) {return ((*_object).*_function)(param1, param2);}	R Execute(P1 param1, P2 param2, P3 param3) {return ((*_object).*_function)(param1, param2, param3);}private:	F _function;	O _object;};//This is where the magic happenstemplate <typename R, typename P1 = EmptyClass, typename P2 = EmptyClass, typename P3 = EmptyClass>class Functor{public:	Functor() {}	template <typename F>	Functor(F value):_function(new FunctionPointer<R, P1, P2, P3, F>(value)) {}	template <typename F, class O>	Functor(const O & object, F func):_function(new MemberPointer<R, P1, P2, P3, F, O>(object, func)) {}	R operator()() {assert(_function != 0); return _function->Execute();}	R operator()(P1 param1) {assert(_function != 0); return _function->Execute(param1);}	R operator()(P1 param1, P2 param2) {assert(_function != 0); return _function->Execute(param1, param2);}	R operator()(P1 param1, P2 param2, P3 param3) {assert(_function != 0); return _function->Execute(param1, param2, param3);}	operator bool() const {return _function != 0;} //Used for testing if we have a function stored	void Clear() {_function = 0;}	template <typename F>	void Set(F value) {_function = new FunctionPointer<R, P1, P2, P3, F>(value);} //smart_ptr will automatically free up old stuff	template <typename F, class O>	void Set(const O & object, F func) {_function = new MemberPointer<R, P1, P2, P3, F, O>(object, func);}private:	smart_ptr<FunctorStorage<R, P1, P2, P3> > _function;};#endif

Now, the beautiful thing about this code is that C++ does not instantiate member functions for templates until they are used, which allows you to get away with defining loads of functions that you may not actually need.

Any way, I hope there's something here to help you.
What Extrarius said is an option. Or a wrapper like you mentioned (but using inheritance). Below some code I just made up (bound to contain mistakes):

// The freelisttemplate <typename T>class FreeList {};class BaseWrapper {  virtual ~BaseWrapper()=0;  virtual void ReFillList()=0;  virtual FreeList<BC> operator -> ()=0;};template <typename T>class DerivedWrapper : public BaseWrapper {  void ReFillList() {    myFreelist.ReFill();  }  FreeList<BC> operator -> () {    return &myFreelist;  };  FreeList<T> myFreelist;};


Although this code involves virtual functions, your FreeList class needn't be altered and can remain generic. A slightly different way of doing basically the same could be to allow DerivedWrapper to inherit from FreeList<T> instead of having one. Of course at that point it's no longer a wrapper.
template <typename T>class DerivedWrapperThingy : public BaseWrapper, public FreeList<T> {  void ReFillList() {    FreeList<T>::ReFill();  }  FreeList<BC> operator -> () {    return this;  };};
don't make it any harder than it is:
struct Base{	virtual void foo(void){ std::cout << "Base::foo()\n";}};struct Derived : public Base{	void foo(void){ std::cout << "Derived::foo()\n";}};template <typename Base, typename T>Base* create(void){ return new T;}template <typename Base>class FreeList{public:	FreeList(Base* (*create)(void) = create<Base, Base>): create( create){}	Base* (*create)(void);};/try it :Dint main(void){	FreeList<Base> base;	FreeList<Base> derived( create<Base, Derived>);	//leaks but shows it works	base.create()->foo();	derived.create()->foo();}

basicy this is a prototype/examplar based apporach for added flexibility you could get rid of the function pointer and give base a "clone" member that way it would be true prototype based or you could bass it some sort of factory object creating base objects.
HardDrop - hard link shell extension."Tread softly because you tread on my dreams" - Yeats
You guys are absolutely beautiful. I ended up using some of your ideas (main rick_appleton's), and had to create private in-class wrapper classes within ObjectFactory. The code isn't truly beautiful, but hell, it works, and I can clean it up later. here is the final code:

template <class BC>class ObjectFactory{	private:		//Built in helper classes.  EWWW		class BaseFreeListWrapper 		{			public:				//virtual ~BaseFreeListWrapper()=0;    //UNEEDED				//virtual FreeList<BC> operator -> ()=0;  //UNEEDED				virtual BC * getInstance() = 0;				virtual void FreeInstance(BC *instance) = 0;		};		template <typename T>		class DerivedFreeListWrapper : public BaseFreeListWrapper 		{			public:				DerivedFreeListWrapper(int iInitialSize, string className)				{					myFreeList = NULL;					myFreeList = new FreeList<T>(iInitialSize, className);				}						~DerivedFreeListWrapper()				{					if(myFreeList != NULL)					{						delete myFreeList;					}				}						/*				inline FreeList<BC> operator -> () {					return *myFreeList;				};				*/								inline BC * getInstance()				{					if(myFreeList)						return myFreeList->getInstance();					return NULL;				}								inline void FreeInstance(BC *instance)				{					if(myFreeList)						myFreeList->FreeInstance((T*)instance);					return;				}			private:				FreeList<T> *myFreeList;		};....


Ratings++ all around!

This topic is closed to new replies.

Advertisement