473,383 Members | 1,929 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,383 software developers and data experts.

Inheritance and STL containers

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
9 2372
<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
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

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
<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
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

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
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

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
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

8
by: Wolfgang Lipp | last post by:
<annotation> the first eleven contributions in this thread started as an off-list email discussion; i have posted them here with the consent of their authors. -- _w.lipp </annotation> From:...
12
by: Glen Able | last post by:
Hello, I've been getting into the STL lately for personal projects and I'm can't decide whether to wrap containers or not. So the choice is whether to have a member variable like this: ...
4
by: KInd | last post by:
Hello All, When is nested class more preferable that Inheritance ? I think with proper inheritance and friend class concept we can get the same flexibility as nested classes Any comments .. Best...
19
by: Mike Tyka | last post by:
Hello community, i'm fairly new to using the STL but i've been experimenting a bit with it. I tried to derive a new class say MyString from string like so: class MyString: public string{...
2
by: Søren Holstebroe | last post by:
Hi there, I'm having a struggle with GNU g++ (3.3.5) and inheritance of typedefs in STL containers. I'm trying to port some old code I wrote with MS Visual C++ and it looks like there is a...
15
by: Nindi73 | last post by:
HI If I define the class DoubleMap such that struct DoubleMap : public std::map<std::string, double>{}; Is there any overhead in calling std::map member functions ? Moreover are STL...
21
by: George Exarchakos | last post by:
Hi everyone, I'd like your help... Can we have a std::list<BASEwhere BASE be the base class of a class hierarchy? I want to add to this list objects that are inherited from BASE class but not...
7
by: wangxiaohu | last post by:
I am trying to write a class myVector based on std::vector and add only a sort method. The sort method needs to access the array stored in the base class using iterator. I have following draft...
4
by: EnsGabe | last post by:
Suppose you have a class heirarchy as such: class Base{ .... }; class Mid1 : public Base{ ....
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.