Jump to content
  • Advertisement
Sign in to follow this  
choffstein

Casting Conundrum

This topic is 4809 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 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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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 happens
template <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.

Share this post


Link to post
Share on other sites
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 freelist
template <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;
};
};

Share this post


Link to post
Share on other sites
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 :D
int 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.

Share this post


Link to post
Share on other sites
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!

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

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

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!