Get Derived (templated class) from Base pointer?
Let's say I have a bunch of objects that are created via a template class:
template<typename TValue, TPolicy1, TPolicy2>
class CDerived
{
TValue _Value;
public:
CDerived(TValue& Val) : _Value(Val) {}
//
TValue& GetValue()
{
return m_Value;
}
//
void DoPolicy1(int i, bool b)
{
TPolicy1::Do(i, b, _Value);
}
//
void DoPolicy2(int i, bool b, _Value)
{
TPolicy2:Do(i, b, _Value);
}
};
The Do() methods in TPolicy1 and TPolicy2 are static template methods, so
CDerived just calls the appropriate static method and passes in _Value,
which is
a template parameter of Do() in TPolicy1 and TPolicy2;
Now I need to store all of these CDerived objects in a generic container.
Since
CDerived is a template class, I can't do this straight away. I have to
create a
base class, CBase, that is not templated.
The goal is that the container can take a CBase* pointers it holds and call
methods on this pointer, and this is important: without having to cast the
CBase* to a KNOWN type, because the *exact* type of CDerived is unknown
because
it templated. I might also add that the policy classes are designed to be
created by users, the purpose being to allow users to customize the behavior
of
CDerived to handle arbitrary TValue objects any way they like.
Here's CBase:
class CBase
{
virtual void DoPolicy1(int i, bool b) = 0;
virtual void DoPolicy2(int i, bool b) = 0;
};
and we'll change class CDerived to class CDerived : public CBase.
So, I create all of my CDerived objects and add them to a container as
CBase*
pointers. Now, let's say the container is a std::vector. I want to be able
to
do something like:
std::string s("test");
CDerived der<std::string, CMyPolicy1, CMyPolicy2>(s);
std::vector<CBase*> vec;
vec.push_back(&der);
...
// and then later
s = vec[0]->GetValue();
My problem is that vec holds CBase* pointers. CBase does not hold the
Value, it
is held in CDerived. GetValue() is in CDerived. It cannot be in CBase
because
the return type varies based on TValue passed into CDerived.
I tried adding an additional virtual function to CBase:
virtual CBase* GetPtr() = 0;
and then creating a typedef in CDerived that is it's current type and
overriding
GetPtr():
typedef CDerived<TValue, TPolicy1, TPolicy2> tThis;
tThis* GetPtr()
{
return this;
}
This still does not work. CBase and CDerive compile fine, because you are
allowed to change the return type in a virtual function if it is compatible
with
the return type from the base class, and CDerived<>* is compatible with
CBase*
since CDerived is derived from CBase.
What does not work is that GetPtr() in CDerived still returns a CBase
pointer,
so I get an error from the compiler that basically "GetValue() is not a
member
of CBase". So, even though I'm returning a tThis* from CDerived's GetPtr(),
the
compiler is casting that back to a CBase* apparently.
So, I think that my ultimate problem is that: given only a CBase*, is there
any
way I can get a CDerived* that is immediately callable, without having to
case
CBase* to a specific CDerived* (of which I don't know the exact type,
because
CDerived is a template class).
I find it interesting that typeid() always seems to know the type of the
most
derived type of a pointer (e.g., typeid(*pBase).name() gives
"CProperty<float,
MyPolicy1, MyPolicy2>), but there appears to be zero support in the language
to
get this information.
It seems to me that the concepts of "generic programming" (templates) and
containers do not play well at all together when the templated objects need
to
be in the containers rather than being the containers.
I've experimented with "chameloeon objects" such as boost::any and two
others,
but the problem with all of them is that while it's easy to add any
arbitrary
type of object to the chameleon, if you want to get the object out you
already
have to know the type of the object so you can either cast the chameleon's
value
or assign it to a variable of the proper type. My problem is that in trying
to
make this generic and easy to use without the user having to write a bunch
of
handle classes or something like that, I have to be able to get a pointer
out of
the container and call it without having to cast it to a CDerived object (of
which I don't know the exact type).
I'm wondering if some kind of template metaprogramming (e.g. TypeLists from
Mr.
Alexandrescu's Modern C++ Design) might offer a solution. I'm also thinking
about an ASM thunk or something like that that allows the base to call the
function in derived, but at this point I'm stumped and wondering if this is
even
possible at all.
~Mike
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]