Re: Deriving from concrete types
"Gene Bushuyev" <spam@spamguard.com> skrev i meddelandet
news:1%pog.161347$F_3.54494@newssvr29.news.prodigy.net...
"kanze" <kanze@gabi-soft.fr> wrote in message
news:1151320889.159116.71540@b68g2000cwa.googlegroups.com...
Bernhard Jungk wrote:
[...]
If the base class isn't designed to be derivable, it shouldn't
be done with public inheritance.
You see. You've mixed the two. Inheritance is a C++
implementation technique; derivation is a design concept. If
the reason you are using inheritance is to implement derivation,
then you should ensure that your class is designed with
derivation in mind. If you are using it for some other reason,
you should ensure that your class meets the requirements for
whatever the reason.
Public inheritance defines a "is a" relationship
Public derivation defines a "is a" relationship.
It may or may not be. I don't favor making subtle distinctions about
inheritance
and derivation, both are used interchangeably to refer to the
mechanism of
creating subtypes in C++.
Going back to the classic work of Barbara Liskov, where she defined
the
substitution principle:
"What is wanted here is something like the following substitution
property: If
for each object o1 of type S there is an object o2 of type T such
that for all
programs P defined in terms of T, the behavior of P is unchanged
when o1 is
substituted for o2 then S is a subtype of T."
But we are not always interested in polymorphic use of the classes.
There is no substitution invoved!
Try this snipet from the standard library:
template<class _ArgT, class _ResultT>
struct unary_function
{
typedef _ArgT argument_type;
typedef _ResultT result_type;
};
template<class _NumT>
struct plus : binary_function<_NumT, _NumT, _NumT>
{
_NumT operator()(const _NumT& _Left, const _NumT& _Right) const
{ return _Left + _Right; }
};
These classes are never dynamically allocated, never accessed trough a
pointer, and never ever assigned to a base class. No slicing, no
delete through pointer to base. Never!
Why do you believe that I cannot use similar hierarchies in my code?
Liskov has nothing to do with this!
That pretty much restricts derivation to virtual functions, - the
only way the
derived class can both extend the base and be reused in place of
base class
without modifications of the existing code. Non-virtual inheritance,
whether
public, private or protected, doesn't satisfy the substitution
principle, it is
simply a way to reuse the base class in the derived. Such reuse
comes with
inheritance member fees, such as interface pollution/collision and
tight
coupling (second only to "friend") and possibility of errors (UB,
slicing) if
substitution is erroneously attempted.
What if substitution is not attempted? How could I assign an apple to
a fruit, when there are no fruit variables in the program?
This reuse can be achieved by
composition, which doesn't have any of those problems, except it
requires
additional typing, which is never a good argument against doing
design
correctly. Of course, there are plenty of simple cases in template
designs of
value classes where the public derivation is an acceptable solution
or the only
solution (e.g. CRTP), with little dangers of something going wrong.
Still I
would do that only when necessary.
And who decides when it is necessary? :-)
Inheriting from a large concrete class like
std::vector is a gratuitous violation of design rules, which has
only problems
and no real advantages.
True.
Bo Persson
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]