By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,018 Members | 870 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,018 IT Pros & Developers. It's quick & easy.

Inheritance and STL containers

P: n/a
I've ran into a problem with inheritance and STL containers. The code
is too much to list, but here is the basic problem:

#include <queue>

using namespace std;

class Base
{
public:
typedef queue<Base *BaseQ;

void DoBase(BaseQ &) {;} // should work on any queue of Base or a Base
subtype
};
class Derived: public Base
{
public:
typedef queue<Derived *DerivedQ;
};

// have other derived types from base: Derived1, Derived2, etc...

int main(int argc, _TCHAR* argv[])
{
Derived *dp = new Derived();
Base *bp(dp); // (A) this is legal as expected (upcasting)

Derived::DerivedQ dv; dv.push(dp);

bp->loopBase(dv); // (B) compiler says this is illegal, cannot convert
from queue<Derived *& to queue<Base *&
return 0;
}

If line (A) is legal, why isn't like (B) legal as well? There are
operations in Base that must apply to containers of any derived of
base. It seems wasteful to have to create a temporary queue<Base *and
load it with the contents of queue<Derived *to call loopBase()
(that's what I do now). Is there a better way?

Jul 27 '06 #1
Share this Question
Share on Google+
9 Replies


P: n/a
<mo********@yahoo.comwrote...
I've ran into a problem with inheritance and STL containers. The code
is too much to list, but here is the basic problem:

#include <queue>

using namespace std;

class Base
{
public:
typedef queue<Base *BaseQ;

void DoBase(BaseQ &) {;} // should work on any queue of Base or a Base
subtype
};
class Derived: public Base
{
public:
typedef queue<Derived *DerivedQ;
};

// have other derived types from base: Derived1, Derived2, etc...

int main(int argc, _TCHAR* argv[])
{
Derived *dp = new Derived();
Base *bp(dp); // (A) this is legal as expected (upcasting)

Derived::DerivedQ dv; dv.push(dp);

bp->loopBase(dv); // (B) compiler says this is illegal, cannot convert
from queue<Derived *& to queue<Base *&
return 0;
}

If line (A) is legal, why isn't like (B) legal as well?
sometemplate<Tand sometemplate<TTare *unrelated* types no matter
what relationship exists between T and TT. Unless they are the same,
any template instantiated from two different types produces two different
types as the result. No conversion exists between two different types
unless explicitly programmed (or part of the language, like int -double).
There are
operations in Base that must apply to containers of any derived of
base. It seems wasteful to have to create a temporary queue<Base *and
load it with the contents of queue<Derived *to call loopBase()
(that's what I do now). Is there a better way?
Just use 'queue<Base*>' and make sure you apply polymorphism there.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jul 27 '06 #2

P: n/a
Ah, I actually fuond a better solution: convert DoBase() to a template
function. Then it wil work:

#include <queue>

using namespace std;

class Base
{
public:
typedef queue<Base *BaseQ;

template <typename T>
void DoBase(queue<T&) {;} // should work on any queue of Base or a
Base subtype
};
class Derived: public Base
{
public:
typedef queue<Derived *DerivedQ;
};

// have other derived types from base: Derived1, Derived2, etc...

int main(int argc, _TCHAR* argv[])
{
Derived *dp = new Derived();
Base *bp(dp); // (A) this is legal as expected (upcasting)

Derived::DerivedQ dv; dv.push(dp);

bp->DoBase<Derived *>(dv); // (B) compiler says this is illegal,
cannot convert from queue<Derived *& to queue<Base *&

return 0;
}

Jul 27 '06 #3

P: n/a

Victor Bazarov wrote:
<mo********@yahoo.comwrote...

sometemplate<Tand sometemplate<TTare *unrelated* types no matter
what relationship exists between T and TT. Unless they are the same,
any template instantiated from two different types produces two different
types as the result. No conversion exists between two different types
unless explicitly programmed (or part of the language, like int -double).
Ok, this is what I try to understand. Why? There may be a good reason,
but I don't know. In by example,
Base *bp;
Derived *dp;
bp = dp; // this is legal and useful

why the compiler not use this convertion? Just trying to understand!

Jul 27 '06 #4

P: n/a
<mo********@yahoo.comwrote...
>
Victor Bazarov wrote:
><mo********@yahoo.comwrote...

sometemplate<Tand sometemplate<TTare *unrelated* types no matter
what relationship exists between T and TT. Unless they are the same,
any template instantiated from two different types produces two different
types as the result. No conversion exists between two different types
unless explicitly programmed (or part of the language, like int ->
double).
Ok, this is what I try to understand. Why?
I am not sure I understand the question... Why should they be related?
How would conversion work? Do you expect the conversion *implicit*? You
can program your own template containers which might provide conversions
from one to the other. My guess for the absence of the implicit conversion
is due to the inability to invent proper semantics for all cases.
There may be a good reason,
but I don't know. In by example,
Base *bp;
Derived *dp;
bp = dp; // this is legal and useful

why the compiler not use this convertion? Just trying to understand!
And do what? Would you expect the compiler to automatically convert
queue<Derived*to queue<Base*or queue<Derived*to queue<Base*>*
or queue<Derived>* to queue<Base>*? What for? Treat all elements of
the container of Derived as if they were Base? You can do it now. Or
something else? What would be the use?

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jul 27 '06 #5

P: n/a
mo********@yahoo.com wrote:
Victor Bazarov wrote:
><mo********@yahoo.comwrote...

sometemplate<Tand sometemplate<TTare *unrelated* types no matter
what relationship exists between T and TT. Unless they are the same,
any template instantiated from two different types produces two different
types as the result. No conversion exists between two different types
unless explicitly programmed (or part of the language, like int -double).
Ok, this is what I try to understand. Why? There may be a good reason,
but I don't know. In by example,
Base *bp;
Derived *dp;
bp = dp; // this is legal and useful

why the compiler not use this convertion? Just trying to understand!
Because they're separate types and there is no inheritance relationship
between them. Just imagine if there were an explicit specialization of
sometemplate<Derived>. Then it might look completely different than
sometemplate<Base>.
Jul 27 '06 #6

P: n/a

Victor Bazarov wrote:
There may be a good reason,
but I don't know. In by example,
Base *bp;
Derived *dp;
bp = dp; // this is legal and useful

why the compiler not use this convertion? Just trying to understand!

And do what? Would you expect the compiler to automatically convert
queue<Derived*to queue<Base*or queue<Derived*to queue<Base*>*
The conversion Derived * to Base * is available implicitly; my
queue<Base *>. I think it's reasonable to expect queue<Base *to be
assigned from a queue<Derived *>
or queue<Derived>* to queue<Base>*? What for? Treat all elements of
What for? For one, I could have a function in Base
Base::DoBase(queue<Base *&) operating on each Base *, but
polymorphism will let each derivation of Base in this queue morph the
behaviour as desired by that derivation. If another part of program has
a queue<Derived *>, but wants to call Base::DoBase with that queue as
the parameter, why not use the Derived * to Base * conversion that is
available?

Ok, 2nd part of my question is what is best solution. I posted a
solution (my last post of 7/27). If DoBase will invoke polymorphic
functions via Base *, then I could change the function declaration to:

template <typename T>
void DoBase(queue<T&) {;}

How about this solution?

ps: Sorry my original post had a typo, the call to function loopBase is
not valid; it should call DoBase.

Jul 28 '06 #7

P: n/a
mo********@yahoo.com wrote:
[..] 2nd part of my question is what is best solution. I posted a
solution (my last post of 7/27). If DoBase will invoke polymorphic
functions via Base *, then I could change the function declaration to:

template <typename T>
void DoBase(queue<T&) {;}

How about this solution?
This solution is not exactly the same. If you pass an object of type
'queue<Derived*>' to 'DoBase', 'T' will be deduced as 'Derived*', and
a new instantiation of 'DoBase' will be created. Any access to the
members of '*T' (Derived) will be made statically:

template <typename T>
void DoBase(queue<T& q) {
/* get the iterator */
(*it)->somemember(); // here '*it' is of type 'Derived*'
}

(although it may not be as bad as it sounds).

What you might want to do is this:

void DoSingleBase(Base* pb) { /* something */ }

template <typename T>
void DoBase(queue<T& q) {
/* get the iterator */
DoSingleBase(*it);
}

In this case the pointer that (*it) yields will be _converted_ to
to Base* and polymorphic behaviour will be ensured.

Or maybe I'm wrong. Try both and see.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jul 28 '06 #8

P: n/a

mo********@yahoo.com wrote:
The conversion Derived * to Base * is available implicitly; my
queue<Base *>. I think it's reasonable to expect queue<Base *to be
assigned from a queue<Derived *>
Maybe you think it is reasonable but it just doesn't work. The two
resultant classes are different and unrelated. It is something you'll
need to learn about templates. You can't copy/assign a queue<intto a
queue<longeither even though there is an implicit conversion. The
queue template would need copy/assignment operators that are templates
taking queue<Tas parameters; it doesn't and neither do any other std
containers that I am aware of.

I'm sure there are reasons why these operators where ommited from the
standard but I don't off hand know them. It is what it is.

Jul 28 '06 #9

P: n/a
mo********@yahoo.com wrote:
[conversion from queue<Derived*to queue<Base*>]

This is in the FAQ:
http://www.parashift.com/c++-faq-lit....html#faq-21.3

and the questions surrounding it.

--
Marcus Kwok
Replace 'invalid' with 'net' to reply
Jul 31 '06 #10

This discussion thread is closed

Replies have been disabled for this discussion.