 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Lars Jordan Guest
|
Posted: Mon Jun 12, 2006 2:42 am Post subject: Templates and derivation |
|
|
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:
// the new holder: assumes now that U provides a member type ImplType and has a
// proxy which can (given a little effort is taken) be used quite transparently.
template<typename U> struct Holder
{
Holder() : m_pU( NULL ) {}
~Holder()
{
if ( m_pU )
{
delete m_pU; m_pU = NULL;
}
}
// this is a helper which is used to keep pointers to objects of "derived"
// classes.
struct BaseProxy
{
BaseProxy() : m_pUImpl( NULL ) {}
~BaseProxy()
{
if ( m_pUImpl )
{
delete m_pUImpl; m_pUImpl = NULL;
}
}
typedef typename U::ImplType ImplType;
ImplType* m_pUImpl;
};
U* m_pU;
BaseProxy m_baseProxy;
};
In addition I need to modify the MF template:
template<typename T> class MF
: public T
{
public:
typedef T ImplType;
};
Now I can write the following code:
int main( int, char*[] )
{
MF<Derived>* pMFD = new MF<Derived>;
Holder<MF<Base> > baseHolder;
baseHolder.m_baseProxy.m_pUImpl = pMFD; // actually this should be hidden
// behind a member function of Holder
return 0;
}
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?
best regards
Lars
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Sektor van Skijlen Guest
|
Posted: Wed Jun 14, 2006 3:28 am Post subject: Re: Templates and derivation |
|
|
Dnia 11 Jun 2006 17:42:53 -0400, Lars Jordan skrobie:
| Quote: | 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?
|
These classes are separate classes, no matter what class was used to
instantiate the template.
You can define a conversion operator in MF template, which will do the
conversion to your "base" class. This will still save the conversion
constraints, so the code won't compile if you try to use this conversion for a
class that is not derived class.
--
// _ ___ Michal "Sektor" Malecki <sektor(whirl)kis.p.lodz.pl>
\\ L_ |/ `| /^\ ,() <ethouris(O)gmail.com>
// \_ |\ \/ \_/ /\ C++ bez cholesterolu: http://www.intercon.pl/~sektor/cbx
"I am allergic to Java because programming in Java reminds me casting spells"
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Manfred von Willich Guest
|
Posted: Wed Jun 14, 2006 3:29 am Post subject: Re: Templates and derivation |
|
|
Lars Jordan wrote:
| Quote: | 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?
|
I have stripped out extras, leaving the minimum. What I have given
compiles successfully, even when using your Holder class. Essentially,
two lines change: the addition of a template operator to template class
MF, and the need for the explicit invocation of this operator to get
the compiler to recognise the conversion.
template<typename T> class MF : public T
{
public:
template<typename B> operator MF<B>& () { return *this; }
};
class Base
{
public:
virtual ~Base() { }
};
class Derived : public Base
{
public:
virtual ~Derived() { }
};
int main( int, char*[] )
{
MF<Derived>* pMFD = new MF<Derived>;
MF<Base>* pMFB = &(MF<Base>&)*pMFD;
return 0;
}
I do not know if it can be done without explicitly invoking a
conversion operator. I hope this is something like what you are
looking for.
Manfred
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
milochen Guest
|
Posted: Wed Jun 14, 2006 3:32 am Post subject: Re: Templates and derivation |
|
|
Lars Jordan wrote:
| Quote: | 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;
}
template<typename T> class MF : public T |
{
public:
typedef T ImplType;
};
| Quote: | From your code you, I know that compile will error ,
since MF<Derived> is not base class of MF<Base> and vice versa. by(7) |
The reason will be more explained in the following context involved by
"==...="
===========Start to explaination============================
Since "template<typename T> class MF : public T " has be defined, so
MF<Base> is a derived class of Base ........(1)
MF<Derived> is a derived class of Derived....(2)
Since "class Derived : public Base",so
Dervied is derived class of Base ...........(3)
Since "template<typename U> struct Holder" you defined, so know that
for any object 'baseHolder' has been defined by 'Holder<U>',
the type of baseHolder.m_pU is 'U*' ........(4)
Since 'Holder<MF<Base> > baseHolder;' you did,
by (4), baseHolder.m_pU is
pointer to MF<Base> whose base class is Base ....(5)
Since "MF<Derived>* pMFD = new MF<Derived>;" you did, so
*pMFD is
pointer to MF<Derived> whose base class is Derived .....(6)
By(5)(6), since you did 'baseHolder.m_pU = pMFD'
so MF<Derived> is not base class of MF<Base> and vice versa. ....(7)
By (7), As long as you want to do 'baseHolder.m_pU = pMFD' successfully
in your code, I have less idea for you to choice as the following
(i)Making that MF<Derived> always able to be a derived class of
MF<Base>,or
(ii)Writting a case function for transformation from MF<Derived> into
MF<Base>.
But I don't
==================End the Explaination=======================
for (i) in Explaination, I don't know how to do that
MF<Derived> is derived class of MF<Base> iff Base is base class of
Derived
And I have no idea for (ii)
My experience is too less, so I just could explain why complier say
error.
I try my effort to make some help to you.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Lars Jordan Guest
|
Posted: Thu Jun 15, 2006 3:32 am Post subject: Re: Templates and derivation |
|
|
Manfred von Willich wrote:
| Quote: | template<typename T> class MF : public T
{
public:
template<typename B> operator MF<B>& () { return *this; }
};
|
To correct myself from the last posting:
I think that the operator becomes a viable option for the compiler for choose
for conversion when the type B is known. This is of course true when the
operator template is instanciated. To convert the result of *thiis (which is
MF<T>& ) to the return type MF<B>& it invokes the instanciated operator itself
thus generating a recursive call.
If anyone could comment on the correctness of this explanation are highly
appreciated.
In addition this leads me to the question of how this behavior can be avoided.
best regards
Lars
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Lars Jordan Guest
|
Posted: Thu Jun 15, 2006 3:35 am Post subject: Re: Templates and derivation |
|
|
Greg Herlihy wrote:
| Quote: | 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.
|
There is only one class template like MF, it's something like
template<typename T> class Object { .... };
which has the purpose of adding some more information to the parameter type T,
like a ref count and an id. It's part of a small library that I am currently
writing on. The holder template is something like a pointer (I don't want to say
smart pointer since I don't know if it's smart ). The resulting constructs
(that the library can deal with) are then for any class X
Pointer<Object<X> > XP; // ;)
And for this I want to keep the semantic of assigning "pointers to Object<Y>" to
"pointers to Object<X>" where Y is publicly derived from X and which are classes
that are provided by the user of the library.
The problem I see with keeping only a T* is that I loose a lot of information -
namely those that come through the instanciation of the Object (MF) class
template with T. Nevertheless, I'll try to apply this approach without the loss
of the additional information kept in the Object class template.
best regards
Lars
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Lars Jordan Guest
|
Posted: Thu Jun 15, 2006 3:37 am Post subject: Re: Templates and derivation |
|
|
Manfred von Willich wrote:
| Quote: | Lars Jordan wrote:
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?
I have stripped out extras, leaving the minimum. What I have given
compiles successfully, even when using your Holder class. Essentially,
two lines change: the addition of a template operator to template class
MF, and the need for the explicit invocation of this operator to get
the compiler to recognise the conversion.
template<typename T> class MF : public T
{
public:
template<typename B> operator MF<B>& () { return *this; }
};
|
What was the compiler that you used? VC8 gives me the warning that the operator
is recursive on all control paths - which leads to a stack overflow. This is
something that I do not understand at all, since I can't see why the same
operator should be called again. If you could give me a hint why this happens
this would be great.
| Quote: | class Base
{
public:
virtual ~Base() { }
};
class Derived : public Base
{
public:
virtual ~Derived() { }
};
int main( int, char*[] )
{
MF<Derived>* pMFD = new MF<Derived>;
MF<Base>* pMFB = &(MF<Base>&)*pMFD;
return 0;
}
I do not know if it can be done without explicitly invoking a
conversion operator. I hope this is something like what you are
looking for.
|
I tried to call it without the explicit invocation of the operator but that
didn't work. It seems that this operator is not a viable option for the compiler
to select automatically for conversion in assignment.
I like the idea of using operators though this is a part of c++ that I do not
know enough about.
regards
Lars
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
milochen Guest
|
Posted: Fri Jun 16, 2006 1:33 am Post subject: Re: Templates and derivation |
|
|
Lars Jordan wrote:
| Quote: | 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:
// the new holder: assumes now that U provides a member type ImplType and has a
// proxy which can (given a little effort is taken) be used quite transparently.
template<typename U> struct Holder
{
Holder() : m_pU( NULL ) {}
~Holder()
{
if ( m_pU )
{
delete m_pU; m_pU = NULL;
}
}
// this is a helper which is used to keep pointers to objects of "derived"
// classes.
struct BaseProxy
{
BaseProxy() : m_pUImpl( NULL ) {}
~BaseProxy()
{
if ( m_pUImpl )
{
delete m_pUImpl; m_pUImpl = NULL;
}
}
typedef typename U::ImplType ImplType;
ImplType* m_pUImpl;
};
U* m_pU;
BaseProxy m_baseProxy;
};
In addition I need to modify the MF template:
template<typename T> class MF
: public T
{
public:
typedef T ImplType;
};
Now I can write the following code:
int main( int, char*[] )
{
MF<Derived>* pMFD = new MF<Derived>;
Holder<MF<Base> > baseHolder;
baseHolder.m_baseProxy.m_pUImpl = pMFD; // actually this should be hidden
// behind a member function of Holder
return 0;
}
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?
best regards
Lars
|
I try my way again try to solve this problem
My direction is that declaring MF<Derived,Base> iff
MF<Derived,Base> is derived class of MF<Base>.
(
pay attention that;
Since you did this, you could consider to ignore to declare
that"Derived:public Base{};" because
"MF<Derived,Base> <=== MF<Base> <===Base"
)
* pMFD = new MF<Derived,Base>;
Holder<MF<Base> > baseHolder;
baseHolder.m_pU = pMFD;
The only compile error is
that "MF<class bestbase,class bestbase>' : base class undefined"
I don't know how to
define MF<class bestbase,class bestbase> in particular.
I don't know whether or not exist a way that to
define MF<class bestbase,class bestbase> particularly.
This is my big problem since I don't know whether the way exist.
Could any body tell me?
Thank you very much.
My Code as the following...
=========================
#include "iostream.h"
class bestbase{};
template<typename DT, typename BT=bestbase> class MF : public DT,
public MF<BT>
{
public:
typedef DT ImplType;
};
class Base
{
public:
virtual ~Base() {}
};
class Derived : public Base
{
public:
virtual ~Derived() {}
};
template<typename U> struct Holder
{
Holder() : m_pU( NULL ) {}
~Holder()
{
if ( m_pU )
{
delete m_pU; m_pU = NULL;
}
}
U* m_pU;
};
int main( int, char*[] )
{
MF<Derived,Base>* pMFD = new MF<Derived,Base>;
Holder<MF<Base> > baseHolder;
baseHolder.m_pU = pMFD;
return 0;
}
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Manfred von Willich Guest
|
Posted: Sun Jun 18, 2006 5:10 am Post subject: Re: Templates and derivation |
|
|
Lars Jordan wrote:
| Quote: | I think that the operator becomes a viable option for the compiler for choose
for conversion when the type B is known. This is of course true when the
operator template is instanciated. To convert the result of *thiis (which is
MF<T>& ) to the return type MF<B>& it invokes the instanciated operator itself
thus generating a recursive call.
|
Lars Jordan wrote:
| Quote: | What was the compiler that you used? VC8 gives me the warning that the operator
is recursive on all control paths - which leads to a stack overflow. This is
something that I do not understand at all, since I can't see why the same
operator should be called again. If you could give me a hint why this happens
this would be great.
|
The compiler I use is VC6 - rather outdated I guess.
I also get a stack overflow upon running it (though I needed to make a
non-template operator for VC6 to actually see it), though still with no
compiler warning. (I use ->operator MF<Base>&() to avoid ambiguity
with the C-style cast).
Looking a little more closely at the conversion function, the compiler
does not know how to convert *this (of type MF<Derived>&) into
MF<Base>&, but we have provided a conversion operator, which it invokes
inside the operator, hence the non-terminating recursive call. It is
easy to assume that the compiler will implicitly convert it this point,
but there is no a valid conversion for it to use. We therefore need
the following conversion:
template<typename B>
operator MF<B>& () { return *reinterpret_cast<MF<B>*>(this); }
BUT: What you are doing is fundamentally flawed (as already suggested
by others in this thread). Look at the following memory layout to see
this (a field is added to each class for illustration).
class Base { int a; };
class Derived : public Base { double b; }
template<typename T> class MF<T> : public T { char c; }
Ignoring the virtual destructor poointer, we have:
Layout of Base: struct { int a; }
Layout of Derived: struct { int a; double b; }
Layout of MF<Derived>: struct { int a; double b; char c; }
Layout of MF<Base>: struct { int a; char c; }
It is clear that the last two are not reinterpret-compatible. Without
any fields in Derived you can probably do this, but it is risky and IMO
bad programming practice. You really should redesign your class
hierarchy. (There is a similar problem with smart pointer templates,
where the smart pointer must be converted to a smart pointer to a base
type, but that is not flawed - reinterpret_cast is not needed.)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|