468,765 Members | 1,011 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 468,765 developers. It's quick & easy.

Inheriting from std::vector?

BCC
Hi,

A colleague has some code like this:

class CMyObject {
// Bunch of Member functions
}

class CMyObjectList: public std::vector<CMyObject>
{
// Bunch of member functions
}

I need to inherit the functionality of his object and list as well as add
some of my own:

class CMyPersonalObject: public CMyObject
{
// More stuff
}

class CMyPersonalObjectList: public CMyObjectList
{
// More stuff
}

But if I pass in CMyPersonalObjectList to a function, and then try to assign
the CMyPersonalObject to a local variable of that type, I get a compiler
error telling me that I cannot convert CMyObject to CMyPersonalObject... the
compiler thinks the list I passed in is made of the parent objects.

What is going on and how do I fix it?

Thanks,
B
Jul 19 '05 #1
26 10243
BCC wrote:

But if I pass in CMyPersonalObjectList to a function, and then try to assign
the CMyPersonalObject to a local variable of that type, I get a compiler
error telling me that I cannot convert CMyObject to CMyPersonalObject... the
compiler thinks the list I passed in is made of the parent objects.

What is going on and how do I fix it?


Would need to see the code where the assignment is made.
However, as std::vector doesn't have a virtual destructor it
shouldn't really be being used as a base class. That isn't
your actual problem though.

Jul 19 '05 #2
On Thu, 23 Oct 2003 23:47:14 GMT, "BCC" <br***@akanta.com> wrote:
A colleague has some code like this:

class CMyObject {
// Bunch of Member functions
}
Missing semicolon.
class CMyObjectList: public std::vector<CMyObject>
{
// Bunch of member functions
}
Ditto.

Without further information this inheritance is a little suspicious.

I can thing of good reasons to inherit from std::string, but not std::vector.

I need to inherit the functionality of his object and list as well as add
some of my own:

class CMyPersonalObject: public CMyObject
{
// More stuff
}

class CMyPersonalObjectList: public CMyObjectList
{
// More stuff
}

But if I pass in CMyPersonalObjectList to a function, and then try to assign
the CMyPersonalObject to a local variable of that type,
There is no relationship between CMyPersonalObjectList and CMyPersonalObject
in what you have shown, so the above seems meaningless.
I get a compiler
error telling me that I cannot convert CMyObject to CMyPersonalObject...
The compiler is right, you cannot do that unless you provide a conversion.
the compiler thinks the list I passed in is made of the parent objects.
Where on earth did you get that absurd idea? Compilers don't think.
What is going on
See e.g. <url: http://news.google.com/>.
and how do I fix it?


Perhaps follow the advice of Michael Moore?

Jul 19 '05 #3
On Thu, 23 Oct 2003 23:47:14 GMT, BCC <br***@akanta.com> wrote:
Hi,

A colleague has some code like this:

class CMyObject {
// Bunch of Member functions
}

class CMyObjectList: public std::vector<CMyObject>
{
// Bunch of member functions
}

I need to inherit the functionality of his object and list as well as add
some of my own:

class CMyPersonalObject: public CMyObject
{
// More stuff
}

class CMyPersonalObjectList: public CMyObjectList
{
// More stuff
}

But if I pass in CMyPersonalObjectList to a function, and then try to
assign
the CMyPersonalObject to a local variable of that type, I get a compiler
error telling me that I cannot convert CMyObject to CMyPersonalObject...
the
compiler thinks the list I passed in is made of the parent objects.

What is going on and how do I fix it?

Thanks,
B


std::vector is a template . CMyObjectList should also be a template, at
least if you want to have personalobject list.

template <class T> CObjectList : public std::vector<T> {
some more
};

typedef CObjectList<CMyPersonalObject> CMyPersonalObjectList;
--
grzegorz
Jul 19 '05 #4
"Alf P. Steinbach" <al***@start.no> wrote in message
news:3f****************@News.CIS.DFN.DE...
the compiler thinks the list I passed in is made of the parent objects.


Where on earth did you get that absurd idea? Compilers don't think.


Understatement of the year. :-)

-Mike

Jul 19 '05 #5

"BCC" <br***@akanta.com> wrote in message
news:6M********************@newssvr21.news.prodigy .com...
Hi,

A colleague has some code like this:

class CMyObject {
// Bunch of Member functions
}

class CMyObjectList: public std::vector<CMyObject>
{
// Bunch of member functions
}

I need to inherit the functionality of his object and list as well as add
some of my own:

class CMyPersonalObject: public CMyObject
{
// More stuff
}

class CMyPersonalObjectList: public CMyObjectList
{
// More stuff
}

But if I pass in CMyPersonalObjectList to a function, and then try to assign the CMyPersonalObject to a local variable of that type, I get a compiler
error telling me that I cannot convert CMyObject to CMyPersonalObject... the compiler thinks the list I passed in is made of the parent objects.
It won't work, because the vector contains CMyObjects, not
CMyPersonalObjects. So whenever you insert a CMyPersonalObject in that
vector, it'll get "truncated" to it's base type. You might be able to use a
vector of pointers to (dynamically-allocated) CMyObjects (+derivatives)
instead, but you'll run into other problems:
- Manual memory allocation is difficult and error-prone (but "smart pointer"
libraries might help, see for example www.boost.org )
- You'll have to downcast the stored addresses all the time
- I think it is wrong to have CMyPersonalObjectList as a subclass of
CMyObjectList, because such hierarchy permits insertions of CMyObjects into
CMyPersonalObjectList (you might want to do a search on "Liskov Substitution
Principle" to learn why this is a bad idea. For example read this article:
http://www.brent.worden.org/articles...rinciple.html).

What exactly are you trying to do? Maybe there's a better way to do it.

What is going on and how do I fix it?

Thanks,
B

Jul 19 '05 #6
Mike Wahler wrote:
"Alf P. Steinbach" <al***@start.no> wrote in message
news:3f****************@News.CIS.DFN.DE...
the compiler thinks the list I passed in is made of the parent objects.


Where on earth did you get that absurd idea? Compilers don't think.

Understatement of the year. :-)


OP must have confused "The Compiler That Thinks" with "The Thinking
Man's Compiler."

/david :-)

--
"As a scientist, Throckmorton knew that if he were ever to break wind in
the echo chamber, he would never hear the end of it."

Jul 19 '05 #7
lilburne wrote:
However, as std::vector doesn't have a virtual destructor it
shouldn't really be being used as a base class.


There is no problem with using it as a base class as long as you don't
destroy the object through a pointer to std::vector.

Jul 19 '05 #8
Rolf Magnus wrote:
lilburne wrote:

However, as std::vector doesn't have a virtual destructor it
shouldn't really be being used as a base class.

There is no problem with using it as a base class as long as you don't
destroy the object through a pointer to std::vector.


And you ensure that how?

Jul 19 '05 #9
lilburne wrote:

Rolf Magnus wrote:
lilburne wrote:

However, as std::vector doesn't have a virtual destructor it
shouldn't really be being used as a base class.

There is no problem with using it as a base class as long as you don't
destroy the object through a pointer to std::vector.


And you ensure that how?


You don't do it.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
Jul 19 '05 #10
Pete Becker wrote:
lilburne wrote:
Rolf Magnus wrote:

lilburne wrote:

However, as std::vector doesn't have a virtual destructor it
shouldn't really be being used as a base class.
There is no problem with using it as a base class as long as you don't
destroy the object through a pointer to std::vector.


And you ensure that how?

You don't do it.


I take it you mean: you don't inherit from a class that
doesn't contain a virtual destructor, not that you don't
delete a pointer to a class that doesn't have a virtual
destructor.

Jul 19 '05 #11
lilburne wrote:

Pete Becker wrote:
lilburne wrote:
Rolf Magnus wrote:
lilburne wrote:

>However, as std::vector doesn't have a virtual destructor it
>shouldn't really be being used as a base class.
There is no problem with using it as a base class as long as you don't
destroy the object through a pointer to std::vector.
And you ensure that how?

You don't do it.


I take it you mean: you don't inherit from a class that
doesn't contain a virtual destructor, not that you don't
delete a pointer to a class that doesn't have a virtual
destructor.


You take it wrong. Pay attention to context.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
Jul 19 '05 #12
Pete Becker wrote:
lilburne wrote:
Pete Becker wrote:

lilburne wrote:
Rolf Magnus wrote:

>lilburne wrote:
>
>
>
>
>>However, as std::vector doesn't have a virtual destructor it
>>shouldn't really be being used as a base class.
>
>
>There is no problem with using it as a base class as long as you don't
>destroy the object through a pointer to std::vector.
>

And you ensure that how?
You don't do it.


I take it you mean: you don't inherit from a class that
doesn't contain a virtual destructor, not that you don't
delete a pointer to a class that doesn't have a virtual
destructor.

You take it wrong. Pay attention to context.


Amazing:

#include <iostream>
#include <memory>

using namespace std;

class A {
public:
A();
~A();
};

class B : public A {
string s;
public:
B();
~B();
};

A::A() { cout << "A::A" << endl;}
A::~A() { cout << "A::~A" << endl;}
B::B() { cout << "B::B" << endl;}
B::~B() { cout << "B::~B" << endl;}

int main()
{
auto_ptr<A> a(new B);
return 0;
}

Jul 19 '05 #13
lilburne wrote:
You take it wrong. Pay attention to context.


Amazing:


You wrote bad code, having been told it's bad. What's your point?

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
Jul 19 '05 #14
Pete Becker wrote:
lilburne wrote:
You take it wrong. Pay attention to context.


Amazing:

You wrote bad code, having been told it's bad. What's your point?


What was bad about it?

Jul 19 '05 #15
lilburne wrote:

Pete Becker wrote:
lilburne wrote:
You take it wrong. Pay attention to context.
Amazing:

You wrote bad code, having been told it's bad. What's your point?


What was bad about it?


PLONK.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
Jul 19 '05 #16
Pete Becker wrote:
lilburne wrote:
Pete Becker wrote:

lilburne wrote:
>You take it wrong. Pay attention to context.
>

Amazing:

You wrote bad code, having been told it's bad. What's your point?


What was bad about it?

PLONK.


Tsk! You jump in to sanction using a class inheritance
design, that not only restricts how the heirarchy may be
used, but which also has the potential to cause resource
leakage, and then become all sniffy.

Its no good simply saying 'don't do it', because it will be
done. If you took 10 'C++' programmers at random and asked
"What does the following program print?" you'd be lucky to
get the correct answer from 4 of them. Ask the 4 that got it
right the same question again having removed virtual from
A's destructor and you might get 2 left.

class A {
public:
virtual void func1() { cout << "a::func1" << endl; }
void func2() { cout << "a::func2" << endl; }
virtual void func3() { cout << "a::func3" << endl; }
virtual ~A() { cout << "a::~a" << endl; }
};

class B {
public:
virtual void func1() { cout << "b::func1" << endl; }
void func2() { cout << "b::func2" << endl; }
void func3() { cout << "b::func3" << endl; }
virtual ~B() { cout << "b::~b" << endl; }
};

int main()
{
B* b = new B;
A* a = b;
a->func1();
a->func2();
a->func3();

b->func1();
b->func2();
b->func3();

delete a;
return 0;
}

Its astonishing how many programmers do not understand the
import of the keyword virtual. But you know that.

Jul 19 '05 #17
On Fri, 24 Oct 2003 21:58:53 +0100, lilburne <li******@godzilla.net> wrote:
Pete Becker wrote:
lilburne wrote:
You take it wrong. Pay attention to context.
Amazing:

You wrote bad code, having been told it's bad. What's your point?


What was bad about it?


You're destroying a non-polymorphic class object polymorphically (through a
pointer to the base class object).

But you knew that.

It's illogical to ban usage of a feature just because that feature _can_
be abused, since almost all language features _can_ be abused, and I think
your use of such an illogical argument was the reason why Pete plonked you.

Jul 19 '05 #18
Alf P. Steinbach wrote:
On Fri, 24 Oct 2003 21:58:53 +0100, lilburne <li******@godzilla.net> wrote:

Pete Becker wrote:

lilburne wrote:
>You take it wrong. Pay attention to context.
>

Amazing:

You wrote bad code, having been told it's bad. What's your point?


What was bad about it?

You're destroying a non-polymorphic class object polymorphically (through a
pointer to the base class object).

But you knew that.

It's illogical to ban usage of a feature just because that feature _can_
be abused, since almost all language features _can_ be abused, and I think
your use of such an illogical argument was the reason why Pete plonked you.


It is unlikely that Pete Becker would derive a class from
a base that has a non-virtual destructure, without some
overriding reason to do so. Because he knows it is a
resource leak waiting to happen, and that safer alternatives
are usually available.

To pretend that you can ensure that the polymorphic deletion
on such a class heirarchy can be avoid just by saying "Don't
do it" is ridiculous. The OP not only has an inheritance
tree of depth four, but is also inheriting from a class that
already exists. As there are already functions in the system
that process the base class polymorphism is going to occur.

Certain language features ought to be used with caution, IMO
one should learn how to use them properly before you start
to abuse them.

Jul 19 '05 #19
On Sat, 25 Oct 2003 02:55:25 +0100, lilburne <li******@godzilla.net> wrote:
Certain language features ought to be used with caution, IMO
one should learn how to use them properly before you start
to abuse them.


Well, modest that I am I find it unlikely that either Pete or I don't
know how to use inheritance properly, and I find it unlikely that either
of us would abuse the mechanism.

Perhaps you're referring to the OP?

But the OP didn't code inheritance from std::vector; he's, er, inherited
that code...

Perhaps, then, you're referring to your own abusive example code?

Jul 19 '05 #20
lilburne wrote:
You wrote bad code, having been told it's bad. What's your point?
What was bad about it?

You're destroying a non-polymorphic class object polymorphically
(through a pointer to the base class object).

But you knew that.

It's illogical to ban usage of a feature just because that feature
_can_ be abused, since almost all language features _can_ be abused,
and I think your use of such an illogical argument was the reason why
Pete plonked you.


It is unlikely that Pete Becker would derive a class from
a base that has a non-virtual destructure, without some
overriding reason to do so. Because he knows it is a
resource leak waiting to happen,


No, it's not. Polymorphically destroying an object of that class is.
A knife can be a useful tool, and it isn't evil. Hoever, using it to
stab people is. Almost everything can be destructive if you want it to
be.
and that safer alternatives are usually available.

To pretend that you can ensure that the polymorphic deletion
on such a class heirarchy can be avoid just by saying "Don't
do it" is ridiculous.
You could also reinterpret_cast the pointer to char* and delete that
one. It will also result in improper deletion. But why would anyone do
such a stupid thing?
Certain language features ought to be used with caution, IMO
one should learn how to use them properly before you start
to abuse them.


Nope. One should learn how to use them and never abuse them at all.

Jul 19 '05 #21
Alf P. Steinbach wrote:
On Sat, 25 Oct 2003 02:55:25 +0100, lilburne <li******@godzilla.net> wrote:

Certain language features ought to be used with caution, IMO
one should learn how to use them properly before you start
to abuse them.

Well, modest that I am I find it unlikely that either Pete or I don't
know how to use inheritance properly, and I find it unlikely that either
of us would abuse the mechanism.

Then why sanction it for others?

Perhaps you're referring to the OP?

But the OP didn't code inheritance from std::vector; he's, er, inherited
that code...
The OP was proposing deriving 3 additional class from it. If
he can't repair the initial inheritance scheme he can at
least not inherit it, or perhaps reduce the potential risk
by giving the initial inheriting class a virtual destructor.
Perhaps, then, you're referring to your own abusive example code?


The code presented isn't abusive. It simply demonstrated the
problem you are likely to have when you have an inheritance
tree whose base consists of a non virtual destructor. It
could even exist in legacy code, which the deriver is
unaware of, and whose original coder certainly wasn't
abusing the language.

Jul 19 '05 #22
Rolf Magnus wrote:
lilburne wrote:

>You wrote bad code, having been told it's bad. What's your point?
>

What was bad about it?
You're destroying a non-polymorphic class object polymorphically
(through a pointer to the base class object).

But you knew that.

It's illogical to ban usage of a feature just because that feature
_can_ be abused, since almost all language features _can_ be abused,
and I think your use of such an illogical argument was the reason why
Pete plonked you.


It is unlikely that Pete Becker would derive a class from
a base that has a non-virtual destructure, without some
overriding reason to do so. Because he knows it is a
resource leak waiting to happen,

No, it's not. Polymorphically destroying an object of that class is.
A knife can be a useful tool, and it isn't evil. Hoever, using it to
stab people is. Almost everything can be destructive if you want it to
be.


As day follows night someone will delete an object of the
class polymorphically, there may already be doing so. There
might be code in the system that deletes pointers of the
base class. They may not, nor should they, even know that
the base pointer they are dealing with is of a derived class.

In any case by inheriting from the base you are implicitly
restricting the problem space that your class can be validly
used in, and you have passed a charged on to maintainence
due to a lazy implementation. All future users of the class
have to remember not to destroy via the base, or to call any
method that might do. But you could have avoid the cost by
using composition rather than inheritance.

Jul 19 '05 #23

lilburne wrote:
[...]
In any case by inheriting from the base you are implicitly
restricting the problem space that your class can be validly
used in, and you have passed a charged on to maintainence
due to a lazy implementation. All future users of the class
have to remember not to destroy via the base, or to call any
method that might do. But you could have avoid the cost by
using composition rather than inheritance.


No thankyou.

http://google.com/groups?selm=3DF9C6...EE37E%40web.de
(Subject: Re: blocking inheritance)

regards,
alexander.
Jul 19 '05 #24
Pete Becker <pe********@acm.org> writes
>>However, as std::vector doesn't have a virtual destructor it
>>shouldn't really be being used as a base class.
>
>
> There is no problem with using it as a base class as long as you don't
> destroy the object through a pointer to std::vector.
>


And you ensure that how?


You don't do it.


I would have thought that would be quite difficult.

If you work as part of a team of developers, or for a large company
where one team expects to reuse code from another team, you'd have to
carefully document the class. Even if your fellow developers remember to
trace the chain of inheritance right back to the base class and check,
how many of them will know that std::vector doesn't have a virtual
destructor? (I didn't know until I read this thread.)

If you're a one man band, you still might post some of your code on the
internet, sell it to somebody, or be very busy and need to subcontract a
project.

Even if you know (somehow) that you will never do the above, you might
need to do a rush job and think: "OK, I can inherit from my XYZ class,
job done and dusted." Then you find yourself in the debugger at three in
the morning, drinking jolt cola or black coffee.

All the same, there are times when I would like to be able to inherit
from a std::vector or other container. I tend to typedef my STL
container declarations:

typedef std::vector<int> CsectorList;

But then I find that I can't forward declare them, because you can't
forward declare a typedef. If I could safely do:

class CsectorList:public std::vector<int>{};

Then I could forward declare this as:

class CsectorList;

Anyone got any ideas for safely achieving this?
--
Simon Elliott
http://www.ctsn.co.uk/


Jul 19 '05 #25
Simon Elliott wrote:
Pete Becker <pe********@acm.org> writes
>However, as std::vector doesn't have a virtual destructor it
>shouldn't really be being used as a base class.
There is no problem with using it as a base class as long as you don't
destroy the object through a pointer to std::vector.
And you ensure that how?
You don't do it.

I would have thought that would be quite difficult.


You know, I know it, ...

All the same, there are times when I would like to be able to inherit
from a std::vector or other container. I tend to typedef my STL
container declarations:

typedef std::vector<int> CsectorList;

But then I find that I can't forward declare them, because you can't
forward declare a typedef. If I could safely do:

class CsectorList:public std::vector<int>{};

Then I could forward declare this as:

class CsectorList;

Anyone got any ideas for safely achieving this?


The question I'd ask is why you want to typedef the thing,
other than to avoid adding #include <vector>. I suppose it
might make it easier to turn it into a std::list, or
whatever, at some later stage. The problem is that you
haven't really hidden the fact that its a vector and haven't
stopped clients from using vector specific operations. I've
been there.

Another motivation I've seen is when someone inherits a
container and adds application specific operations to the
new class. The problem with this is that clients can still
treat it as a bare std::container circumventing any
application specific invariants you might want to impose.
IOW you don't protect access to the container.

Personally I'd either seperate the container specific
element from the application specific operations, or use the
has-a relationship between the classes. I prefer the later.
The result is I believe more robust over time.

Jul 19 '05 #26
lilburne <li******@godzilla.net> writes
The question I'd ask is why you want to typedef the thing,
other than to avoid adding #include <vector>. I suppose it
might make it easier to turn it into a std::list, or
whatever, at some later stage.
There's the clarity issue as well. This is discussed quite well here:

http://www.gotw.ca/gotw/046.htm

But I'm fairly sure that you still have to #include <vector>. More
unpleasantly, if your container is a
std::vector<large_nontrivial_class>

you also need to #include "large_nontrivial_class.h"

So classes which didn't need to know about either std::vector or
large_nontrivial_class still need both includes.

If we were to inherit from std::container<large_nontrivial_class>, the
inherited class could be forward declared and neither of these includes
would be necessary.
The problem is that you
haven't really hidden the fact that its a vector and haven't
stopped clients from using vector specific operations. I've
been there.

Another motivation I've seen is when someone inherits a
container and adds application specific operations to the
new class. The problem with this is that clients can still
treat it as a bare std::container circumventing any
application specific invariants you might want to impose.
IOW you don't protect access to the container.
You could always inherit from it privately, but see below.
Personally I'd either seperate the container specific
element from the application specific operations, or use the
has-a relationship between the classes. I prefer the later.
The result is I believe more robust over time.


Yes, and this would also be safer if the container had not got a virtual
destructor. On the other hand, there may be some usefulness in exposing
the underlying container, as this allows users to apply all the generic
algorithms from the standard library to your class.
--
Simon Elliott
http://www.ctsn.co.uk/


Jul 19 '05 #27

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

18 posts views Thread by Janina Kramer | last post: by
17 posts views Thread by Michael Hopkins | last post: by
8 posts views Thread by Ross A. Finlayson | last post: by
32 posts views Thread by zl2k | last post: by
56 posts views Thread by Peter Olcott | last post: by
9 posts views Thread by aaragon | last post: by
reply views Thread by zhoujie | last post: by
reply views Thread by Marin | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.