Is it ok to inherit from vector?

F

Freddy Flares

Like this.

/********************/
class Card {
public:
Card() : rank(0), suit(0) {}
...
private:
int rank;
int suit;
};

class Cards : public vector<Card> {
public:
Cards();
...
};
/********************/

What about other STL types like string?

Thanks.
 
G

Gianni Mariani

Freddy said:
Like this.

/********************/
class Card {
public:
Card() : rank(0), suit(0) {}
...
private:
int rank;
int suit;
};

class Cards : public vector<Card> {
public:
Cards();
...
};
/********************/

What about other STL types like string?


Yes sure - no problems as long as any vector created with "Cards" is
destroyed from Cards's destructor.

Apart from this, the rest you'll hear is religion.

G
 
J

John Brown

Yes sure - no problems as long as any vector created with "Cards" is
destroyed from Cards's destructor.

Apart from this, the rest you'll hear is religion.

I agree. People like to quote ad nauseam about the lack of "virtual
destructors" and "concrete" classes (including Stroustrup himself) but it's
bunk no matter what the purists say (and with 20 years in the field I know
what I'm talking about). If done properly it's not a problem.
 
C

Cy Edmunds

Freddy Flares said:
Like this.

/********************/
class Card {
public:
Card() : rank(0), suit(0) {}
...
private:
int rank;
int suit;
};

class Cards : public vector<Card> {
public:
Cards();
...
};
/********************/

What about other STL types like string?

Thanks.

I don't think it's a good idea. Standard containers aren't really designed
to be base classes. I think generally that encapulation is a better paradigm
than inheritance unless you are designing a set of polymorphic classes. The
attractive thing about using inheritance with concrete types is that it can
save you a little typing. But encapsulation is more flexible and
maintainable IMHO.

Of course encapsulation and inheritance can both be a waste of time if your
only purpose is to add some functions. Just use functions! e.g.

typedef std::vector<Card> Deck;

void shuffle(Deck &);
Card deal(Deck &);
const Card& peek(const Deck &);

etc. This is actually a very clean design approach in a lot of cases.
 
B

Bronek Kozicki

class Cards : public vector<Card> {
What about other STL types like string?

it's legal, but it's also dangerous, which means bad design. You'd
rather use encapsulation or free functions accepting (vector<Card>&)
parameter. Or if you really want to use inheritance, try this:

class Cards : protected vector<Card>{
using vector<Card>::size; // etc.



B.
 
T

tom_usenet

I agree. People like to quote ad nauseam about the lack of "virtual
destructors" and "concrete" classes (including Stroustrup himself) but it's
bunk no matter what the purists say (and with 20 years in the field I know
what I'm talking about). If done properly it's not a problem.

I disagree. I agree that the virtual destructor problem is a minor
thing. However, a much more major thing is the fact that Cards
probably has class invariants that vector<Cards> doesn't. For a start
there should perhaps be a separate Pack class and Hand class. Exposing
the whole vector interface may cause difficult to track down bugs in
the future, unless the Cards class is only used internally.

Deriving from a container is generally a "quick hack" that you end up
having to refactor in the long run anyway.

Tom
 
J

John Brown

I disagree. I agree that the virtual destructor problem is a minor
thing. However, a much more major thing is the fact that Cards
probably has class invariants that vector<Cards> doesn't. For a start
there should perhaps be a separate Pack class and Hand class. Exposing
the whole vector interface may cause difficult to track down bugs in
the future, unless the Cards class is only used internally.

Actually I agree with you. A restricted interface is typically necessary
though you can employ "using" statements to privatize public base class
members if you want (unbeknownst to many developers though it's an ugly
approach IMO). My real beef lies with those pedantic arguments that state
you absolutely must not do it:

a) Because of the virtual destructor issue
b) Because it's a "concrete" class not intended for further derivation

Well item a isn't an issue if properly controlled and item b is just a
pie-in-the-sky philosophy. Why should someone write a regular (non-member)
"toupper()" function for instance when it's cleaner to derive "MyString"
from "std::string" and implement a member function that does this instead.
It fits naturally into the OOP model and is therefore much cleaner
(especially for strings and vectors which are a staple of most projects).
Therefore, for a generic "vector" class it's ok to derive from it in many
circumstances (to add additional functionality in a controlled environment
for instance). When you need a restricted interface then you can consider
encapsulation.
 
C

Cy Edmunds

John Brown said:
Actually I agree with you. A restricted interface is typically necessary
though you can employ "using" statements to privatize public base class
members if you want (unbeknownst to many developers though it's an ugly
approach IMO). My real beef lies with those pedantic arguments that state
you absolutely must not do it:

a) Because of the virtual destructor issue
b) Because it's a "concrete" class not intended for further derivation

Well item a isn't an issue if properly controlled and item b is just a
pie-in-the-sky philosophy. Why should someone write a regular (non-member)
"toupper()" function for instance when it's cleaner to derive "MyString"
from "std::string" and implement a member function that does this instead.

Great. Now you have two versions of std::string floating around which differ
only in that one has a new member function. If I want to use your toupper
function but only have a std::string available I have to convert to a
different class just to use it. If I *don't* want to use your toupper
function I can't just ignore it -- for instance when somebody passes me a
MyString I have to look up what it is. And what if I wan't to add a second
function? Should I make a third string class? You have neatly outlined why
you should never do what you are advising.
It fits naturally into the OOP model and is therefore much cleaner

(especially for strings and vectors which are a staple of most projects).
Therefore, for a generic "vector" class it's ok to derive from it in many
circumstances (to add additional functionality in a controlled environment
for instance). When you need a restricted interface then you can consider
encapsulation.

I agree that some writers get carried away with pedantic arguments about
concrete base classes, but I think the rest of your argument is nonsense.
 
B

Bronek Kozicki

It fits naturally into the OOP model and is therefore much cleaner
(especially for strings and vectors which are a staple of most projects).
Therefore, for a generic "vector" class it's ok to derive from it in many

what you advise here is just against OOP. It is called
"strong coupling" and "mixing interface with implementation".


B.
 
L

lilburne

John said:
I agree. People like to quote ad nauseam about the lack of "virtual
destructors" and "concrete" classes (including Stroustrup himself) but it's
bunk no matter what the purists say (and with 20 years in the field I know
what I'm talking about). If done properly it's not a problem.

You have to be sure that nobody ever decides to delete your
derived class via a base class pointer. As time goes on the
likelihood is that someone will, then you have undefined
behaviour.

Here is an example that results in segmentation error in
addition to the memory leak, if you uncomment the int b in A.

#include <vector>

class A {
int a;
// int b;
public:
virtual ~A() {};

};

class B : public std::vector<int> {
public:
virtual ~B() {};
};

class C: public A , public B {
public:
};

C* f()
{
new C;
}


int main()
{
std::vector<int>* b = f();
delete b;
return 0;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,146
Messages
2,570,832
Members
47,374
Latest member
EmeliaBryc

Latest Threads

Top