Re: inheriting from std::vector bad practice?
On Apr 3, 6:18 pm, Stuart Golodetz
<sgolod...@NdOiSaPlA.pMiPpLeExA.ScEom> wrote:
Leigh Johnston wrote:
[...]
Some people eschew the derivation of the standard library
containers however the only issues to be aware of are 1)
that their destructors are not virtual and 2) the need to
ensure that the derived class's invariant is not broken by
calling the container's member functions which is only a
problem if the derived class's invariant consists of more
than just the container's invariant (i.e. contains
additional state which depends on the container's state)
which should not be the case if interface augmentation only
is being performed.
I'm wary of wading into this argument, except in so far as I
would add that in this case the other issue to consider is
whether tying yourself down to implementing Path as a
std::vector is a good idea long-term. That's not an issue to
do with inheriting from standard containers (so I guess it
doesn't augment your list above per se), but it is a general
design issue.
That's always something to consider. Of course, he could always
change the base class later, to e.g std::deque<Point2D>, for
example. In the end, the question is how much of the
std::vector interface does he want to expose. From what little
we know, I'd guess all of it. Whether this is a good idea or
not is, as you say, a design issue; if this type is fundamental
to his application, there are very strong arguments for wrapping
it. Not to provide additional functions, but to not provide
some of the existing ones, thus making a later change in the
data structure signficantly simpler, should this become
necessary. (In practice, I think that there are some cases
where it is perfectly clear that std::vector is the only
appropriate data structure. Probably less than is generally
thought, but they do exist.)
As far as inheriting from standard containers go, it's
certainly the case that designs which do so end up violating
the Liskov Substitution Principle. In particular, you can't
pass a pointer to an instance of the subclass to a function
which calls delete on a pointer to the superclass without
invoking undefined behaviour. Whether this matters to you or
not is up to you (and I won't offer an opinion here) -- but
that's at least one consideration to bear in mind when
deciding.
Never allocating a standard container dynamically seems like a
reasonable coding guideline to me, in which case, deletion
through a pointer to base becomes a non-issue.
PS: if it's not yet completely clear: I'm not really arguing
either side here. I think that there are sufficient arguments
for both sides.
--
James Kanze