Re: Templates and derivation
Lars Jordan wrote:
Hi,
I have a question concerning the usage of templates in conjunction with
derivation. I have the following definitions:
template<typename T> class MF : public T
{
public:
typedef T ImplType;
};
class Base
{
public:
virtual ~Base() {}
};
class Derived : public Base
{
public:
virtual ~Derived() {}
};
Then there exists a relationship between Base and Derived which lets me convert
Derived* to Base*.
Furthermore I have a definition
// to keep it simple I use struct with public access.
template<typename U> struct Holder
{
Holder() : m_pU( NULL ) {}
~Holder()
{
if ( m_pU )
{
delete m_pU; m_pU = NULL;
}
}
U* m_pU;
};
Then I have the problem that I cannot do the following thing since instanciating
a template with the Base and the Derived class doesn't "preserve the
convertibility".
int main( int, char*[] )
{
MF<Derived>* pMFD = new MF<Derived>;
Holder<MF<Base> > baseHolder;
baseHolder.m_pU = pMFD; // <-- compile error: MF<Derived>* not convertible to
// MF<Base>*
return 0;
}
To get around this I need a little help from the template parameter of Holder
and little more functionality within holder:
[description of a proxy class template omitted]
My question is. Are there other solutions which solve the problem from described
above? Is there a solution which avoids the usage of such a ImplType-like member?
The problem as I understand it is that pMFD cannot be assigned to
baseHolder.m_pU because the pointer type of the source (MF<Derived>)
does not inherit from the pointer type of the destination (MF<Base>).
However, since both types do inherit from Base (just not from each
other), the assignment would be legal if baseHolder.m_pU were declared
a pointer to type T instead of a pointer to MF<T> whenever Holder is
instantiated with a MF template class.
And in fact a class template specialization can do exactly that:
template<class T>
struct Holder<MF<T> >
{
Holder() : m_pU( NULL ) {}
~Holder()
{
delete m_pU;
}
T* m_pU;
};
One drawback with template specializations however is that they do not
scale very well. So if there are several classes like MF that require
their own special m_pU declarations then a more systematic approach is
warranted. So instead of multiple Holder specializations, the approach
is to specialize a helper class template that describes just the
relationship between T and m_pU's pointer's type:
template <class T>
struct HeldPointerType
{
typedef T type;
};
template <class T>
struct HeldPointerType<MF<T> >
{
typedef T type;
};
template<typename T> struct Holder
{
Holder() : m_pU( NULL ) {}
~Holder()
{
delete m_pU;
}
typename HeldPointerType<T>::type * m_pU;
};
Greg
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]