template<class T>
class Foo
{
public:
T* member;
};
class Base
{
};
typedef Foo<Base> BaseFoo;
class Derived
{
};
typedef Foo<Derived> DerivedFoo;
int main(int argc, char** argv)
{
DerivedFoo* dfoo = new DerivedFoo();
BaseFoo* bfoo = dfoo;
return 0;
}
doesn't compile, the compiler says "cannot convert DerivedFoo* to
BaseFoo* in initialization". How can I fix it? Of course, this one works:
Derived* derived = new Derived();
Base* base = derived;
I know that something similiar (but not really the same) is possible,
because shared_ptr can do it, e.g. this one compiles with g++ 4.3.2:
#include <tr1/memory>
using namespace std::tr1;
class Base
{
};
typedef shared_ptr<Base> BasePtr;
class Derived : public Base
{
};
typedef shared_ptr<Derived> DerivedPtr;
int main(int argc, char** argv)
{
DerivedPtr dptr(new Derived());
BasePtr bptr = dptr;
return 0;
}
--
Frank Buss, http://www.frank-buss.de
piano and more: http://www.youtube.com/user/frankbuss
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
In consideration of what you wrote later combined with your
chosen naming conventions, I assume this was actually
meant to be:
class Derived : public Base
{
};
> typedef Foo<Derived> DerivedFoo;
>
> int main(int argc, char** argv)
> {
> DerivedFoo* dfoo = new DerivedFoo();
> BaseFoo* bfoo = dfoo;
> return 0;
> }
>
> doesn't compile, the compiler says "cannot convert ‘DerivedFoo*’ to
> ‘BaseFoo*’ in initialization". How can I fix it? Of course, this one works:
>
> Derived* derived = new Derived();
> Base* base = derived;
>
> I know that something similiar (but not really the same) is possible,
> because shared_ptr can do it, e.g. this one compiles with g++ 4.3.2:
>
> #include <tr1/memory>
>
> using namespace std::tr1;
>
> class Base
> {
> };
>
> typedef shared_ptr<Base> BasePtr;
>
> class Derived : public Base
> {
> };
>
> typedef shared_ptr<Derived> DerivedPtr;
>
> int main(int argc, char** argv)
> {
> DerivedPtr dptr(new Derived());
> BasePtr bptr = dptr;
> return 0;
> }
It is quite easy to simulate a behaviour that follows
the strategy of shared_ptr, unique_ptr, and similar
classes that can reasonably accept specializations
for different types than the own one. But it is impossible
to "simulate" a base-derived relationship without
introducing such a relation.
The first question is: Why do you need the template,
if you want a specific class hierarchy? Either Foo is
supposed to be some form of a smart pointer, then
there is no reason to create objects in the free store
and to require base-derived relations among smart
pointers. Or Foo is something else, but the question
is: What does it model?
HTH & Greetings from Bremen,
Daniel Krügler
--
Ok, let's assume Foo<T> has a default constructor that initializes
'member' with a null pointer.
> class Base
> {
> };
>
> typedef Foo<Base> BaseFoo;
>
> class Derived
> {
> };
It seems, you forgot to add Base as a base class for Derived here.
> typedef Foo<Derived> DerivedFoo;
>
> int main(int argc, char** argv)
> {
> DerivedFoo* dfoo = new DerivedFoo();
> BaseFoo* bfoo = dfoo;
> return 0;
> }
Why do you 'new' DerivedFoo here?
> doesn't compile, the compiler says "cannot convert ‘DerivedFoo*’ to
> ‘BaseFoo*’ in initialization".
DerivedFoo and BaseFoo are two distinct types that have no inheritence
relationship. But you can make a DerivedFoo convertible to a BaseFoo
and this is probably what you really wanted to do:
int main(int argc, char** argv)
{
DerivedFoo dfoo;
BaseFoo bfoo = dfoo;
return 0;
}
You can do this by providing a templated conversion constructor in the
Foo class template:
template<class T>
class Foo
{
public:
T* member;
Foo() : member(0) {} // default ctor
template<class U>
Foo(Foo<U> const& f) : member(f.member) {}
};
As a bonus you might want to disable this templated conversion
constructor in case U* is not convertible to T* for overloading
reasons. It's possible with a bit of meta-programming but I think this
would be too much information for now.
> I know that something similiar (but not really the same) is possible,
> because shared_ptr can do it, e.g. this one compiles with g++ 4.3.2:
> [...]
> typedef shared_ptr<Base> BasePtr;
> typedef shared_ptr<Derived> DerivedPtr;
>
> int main(int argc, char** argv)
> {
> DerivedPtr dptr(new Derived());
> BasePtr bptr = dptr;
> return 0;
> }
Right. The thing is DerivedPtr is convertible to BasePtr but the types
are not reference-related because there is no inheritence relationship
between these two types. And since they are not reference-related you
cannot use a pointer of type BasePtr* to point to an object of type
DerivedPtr.
Maybe the typedefs are confusing you. You are aware of the fact that
BasePtr* is a pointer to a struct containing a pointer to Base, right?
The inheritence relationship is only between Base and Derived, not
between BasePtr and DerivedPtr. Is it possible that you missed one
level of indirection?
Cheers!
SG
--
>> class Derived
>> {
>> };
>
> It seems, you forgot to add Base as a base class for Derived here.
Yes, this was a copy and paste error.
>
>> typedef Foo<Derived> DerivedFoo;
>>
>> int main(int argc, char** argv)
>> {
>> DerivedFoo* dfoo = new DerivedFoo();
>> BaseFoo* bfoo = dfoo;
>> return 0;
>> }
>
> Why do you 'new' DerivedFoo here?
The real problem was a bit more complicated: Sometimes I have member
variables and methods like this:
DerivedFoo m_dfoo;
DerivedFoo* getDerivedFoo() { return &m_dfoo; }
and sometimes like this:
BaseFoo m_bfoo;
BaseFoo* getBaseFoo() { return &m_bfoo; }
And finally I have methods, which accepts BaseFoo*, only. I can't use
Base*, because I need functionality from the Foo template, e.g. providing
meta-information, like the member variable name of a Foo object in the
containing class.
> DerivedFoo and BaseFoo are two distinct types that have no inheritence
> relationship. But you can make a DerivedFoo convertible to a BaseFoo
> and this is probably what you really wanted to do:
>
> int main(int argc, char** argv)
> {
> DerivedFoo dfoo;
> BaseFoo bfoo = dfoo;
> return 0;
> }
>
> You can do this by providing a templated conversion constructor in the
> Foo class template:
>
> template<class T>
> class Foo
> {
> public:
> T* member;
> Foo() : member(0) {} // default ctor
>
> template<class U>
> Foo(Foo<U> const& f) : member(f.member) {}
> };
Thanks, that's interesting, but doesn't help for my case. Now I have moved
all members from Derived to Base, with some virtual methods. There are not
many, the main difference is the constructor of "Derived", and this works.
Maybe I have to refactor the architecture later a bit, when I have some
more time, e.g. not using templates, but moving the functionality of the
Foo template to some base class of Base.
--
Frank Buss, http://www.frank-buss.de
piano and more: http://www.youtube.com/user/frankbuss
[ See http://www.gotw.ca/resources/clcm.htm for info about ]