Re: Warning

Discussion in 'C++' started by Alf P. Steinbach, Mar 3, 2010.

  1. * Leigh Johnston:
    > Warning: contact with this newsgroup can result in exposure to toxic
    > opinions the treatment of which involves the use of copious amounts of
    > thinking for yourself.


    :)

    IMHO you're absolutely right -- but it applies to any newsgroup!

    On the other hand, ..., well, wait, I'm not opening that can.

    But on the third and gripping hand, while the opinion that I think triggered
    that blast, "don't derive from concrete classes", may not be the world's best
    advice, it is a practice that works for some kinds of problems. For example,
    original COM was built on something very similar to that idea, "don't expose
    derivation from concrete classes to client code". But I think that even that
    more limited idea was shown to be too drastic, when COM+ did away with it. :)


    Cheers,

    - Alf
    Alf P. Steinbach, Mar 3, 2010
    #1
    1. Advertising

  2. * Leigh Johnston:
    >
    >
    > "Alf P. Steinbach" <> wrote in message
    > news:hmmfnk$i2s$-september.org...
    >> * Leigh Johnston:
    >>> Warning: contact with this newsgroup can result in exposure to toxic
    >>> opinions the treatment of which involves the use of copious amounts
    >>> of thinking for yourself.

    >>
    >> :)
    >>
    >> IMHO you're absolutely right -- but it applies to any newsgroup!
    >>
    >> On the other hand, ..., well, wait, I'm not opening that can.
    >>
    >> But on the third and gripping hand, while the opinion that I think
    >> triggered that blast, "don't derive from concrete classes", may not be
    >> the world's best advice, it is a practice that works for some kinds of
    >> problems. For example, original COM was built on something very
    >> similar to that idea, "don't expose derivation from concrete classes
    >> to client code". But I think that even that more limited idea was
    >> shown to be too drastic, when COM+ did away with it. :)
    >>

    >
    > COM does not mandate that policy;


    Well, you then continue saying that it does:


    > it says nothing on how a particular
    > server class is implemented, i.e. a server class could be implemented by
    > a number of classes related through inheritance. All that is exposed to
    > the client is the abstract interface (a collection of public pure
    > virtual functions).


    So, that's a self-contradiction.

    Which means that readers must think for themselves.


    Cheers,

    - Alf
    Alf P. Steinbach, Mar 3, 2010
    #2
    1. Advertising

  3. Alf P. Steinbach

    Ian Collins Guest

    Alf P. Steinbach wrote:
    > * Leigh Johnston:
    >> Warning: contact with this newsgroup can result in exposure to toxic
    >> opinions the treatment of which involves the use of copious amounts of
    >> thinking for yourself.

    >
    > :)
    >
    > IMHO you're absolutely right -- but it applies to any newsgroup!
    >
    > On the other hand, ..., well, wait, I'm not opening that can.
    >
    > But on the third and gripping hand, while the opinion that I think
    > triggered that blast, "don't derive from concrete classes", may not be
    > the world's best advice, it is a practice that works for some kinds of
    > problems.


    Maybe "avoid deriving publicly form concrete classes" would be better
    advice? It certainly applies to standard containers.

    --
    Ian Collins
    Ian Collins, Mar 3, 2010
    #3
  4. Alf P. Steinbach

    Ian Collins Guest

    Leigh Johnston wrote:
    >
    >
    > "Ian Collins" <> wrote in message
    > news:...
    >> Alf P. Steinbach wrote:
    >>> * Leigh Johnston:
    >>>> Warning: contact with this newsgroup can result in exposure to toxic
    >>>> opinions the treatment of which involves the use of copious amounts
    >>>> of thinking for yourself.
    >>>
    >>> :)
    >>>
    >>> IMHO you're absolutely right -- but it applies to any newsgroup!
    >>>
    >>> On the other hand, ..., well, wait, I'm not opening that can.
    >>>
    >>> But on the third and gripping hand, while the opinion that I think
    >>> triggered that blast, "don't derive from concrete classes", may not
    >>> be the world's best advice, it is a practice that works for some
    >>> kinds of problems.

    >>
    >> Maybe "avoid deriving publicly form concrete classes" would be better
    >> advice? It certainly applies to standard containers.
    >>

    >
    > Not true, take a look at http://i42.co.uk/stuff/mutable_set.htm


    A counter example doesn't negate a general guideline. There will always
    be cases where a guideline doesn't apply because a guideline is only a
    recommendation, not a rule. I would use private derivation for the
    example in TC++PL, the interface class is changing the behaviour of
    std::vector, so it should only expose interfaces that comply with the
    change (consider what would happen if the user mixed at() with [] access).

    I still maintain that "avoid deriving publicly from concrete classes" is
    a valid guideline. Any advice that saves the novice unnecessary grief
    should be welcome and I've seen nasty bugs caused by improper use of
    pointers to concrete base classes.

    --
    Ian Collins
    Ian Collins, Mar 3, 2010
    #4
  5. * Leigh Johnston:
    >
    >
    > "Alf P. Steinbach" <> wrote in message
    > news:hmmii4$5jk$-september.org...
    >> * Leigh Johnston:
    >>>
    >>>
    >>> "Alf P. Steinbach" <> wrote in message
    >>> news:hmmfnk$i2s$-september.org...
    >>>> * Leigh Johnston:
    >>>>> Warning: contact with this newsgroup can result in exposure to
    >>>>> toxic opinions the treatment of which involves the use of copious
    >>>>> amounts of thinking for yourself.
    >>>>
    >>>> :)
    >>>>
    >>>> IMHO you're absolutely right -- but it applies to any newsgroup!
    >>>>
    >>>> On the other hand, ..., well, wait, I'm not opening that can.
    >>>>
    >>>> But on the third and gripping hand, while the opinion that I think
    >>>> triggered that blast, "don't derive from concrete classes", may not
    >>>> be the world's best advice, it is a practice that works for some
    >>>> kinds of problems. For example, original COM was built on something
    >>>> very similar to that idea, "don't expose derivation from concrete
    >>>> classes to client code". But I think that even that more limited
    >>>> idea was shown to be too drastic, when COM+ did away with it. :)
    >>>>
    >>>
    >>> COM does not mandate that policy;

    >>
    >> Well, you then continue saying that it does:
    >>
    >>
    >>> it says nothing on how a particular server class is implemented, i.e.
    >>> a server class could be implemented by a number of classes related
    >>> through inheritance. All that is exposed to the client is the
    >>> abstract interface (a collection of public pure virtual functions).

    >>
    >> So, that's a self-contradiction.
    >>
    >> Which means that readers must think for themselves.
    >>
    >>

    >
    > You said original COM has built on the idea that you don't derive from
    > concrete classes and I was contradicting that: you can have a class
    > hierarchy that implements a particular COM interface, i.e. there doesn't
    > need to be a one-to-one mapping between a COM interface and a single


    Yes, except for lack of attention to detail you're violently agreeing with me. :)

    Note what you quoted. It's not the same as your paraphrase.


    Cheers,

    - Alf
    Alf P. Steinbach, Mar 3, 2010
    #5
  6. Alf P. Steinbach

    Ian Collins Guest

    Leigh Johnston wrote:
    >
    >
    > "Ian Collins" <> wrote in message
    > news:...
    >> Leigh Johnston wrote:
    >>>
    >>>
    >>> "Ian Collins" <> wrote in message
    >>> news:...
    >>>> Alf P. Steinbach wrote:
    >>>>> * Leigh Johnston:
    >>>>>> Warning: contact with this newsgroup can result in exposure to
    >>>>>> toxic opinions the treatment of which involves the use of copious
    >>>>>> amounts of thinking for yourself.
    >>>>>
    >>>>> :)
    >>>>>
    >>>>> IMHO you're absolutely right -- but it applies to any newsgroup!
    >>>>>
    >>>>> On the other hand, ..., well, wait, I'm not opening that can.
    >>>>>
    >>>>> But on the third and gripping hand, while the opinion that I think
    >>>>> triggered that blast, "don't derive from concrete classes", may not
    >>>>> be the world's best advice, it is a practice that works for some
    >>>>> kinds of problems.
    >>>>
    >>>> Maybe "avoid deriving publicly form concrete classes" would be
    >>>> better advice? It certainly applies to standard containers.
    >>>>
    >>>
    >>> Not true, take a look at http://i42.co.uk/stuff/mutable_set.htm

    >>
    >> A counter example doesn't negate a general guideline. There will
    >> always be cases where a guideline doesn't apply because a guideline is
    >> only a recommendation, not a rule. I would use private derivation for
    >> the example in TC++PL, the interface class is changing the behaviour
    >> of std::vector, so it should only expose interfaces that comply with
    >> the change (consider what would happen if the user mixed at() with []
    >> access).
    >>
    >> I still maintain that "avoid deriving publicly from concrete classes"
    >> is a valid guideline. Any advice that saves the novice unnecessary
    >> grief should be welcome and I've seen nasty bugs caused by improper
    >> use of pointers to concrete base classes.
    >>

    >
    > I am sorry but this is just absolute garbage; there is absolutely
    > nothing wrong with deriving publicly or otherwise from concrete
    > classes.


    No, it isn't. Consider a trivial example based on the cited TC++PL
    reference:

    #include <iostream>
    #include <vector>

    class Vector : public std::vector<int> {
    int lb;
    public:
    Vector( int low, int high )
    : std::vector<int>(high-low+1), lb(low) {}

    int& operator[](int i) { return std::vector<int>::eek:perator[](i-lb); }
    };

    template <typename T> void f( const std::vector<T>& v ) {
    std::cout << v[1] << std::endl;
    }

    int main() {
    Vector vec(1,10);

    vec[1] = 42;

    std::cout << vec.at(1) << std::endl;
    f( vec );
    }

    > The standard containers are not designed to be derived from if
    > you consider that they do not have a virtual destructor but I have given
    > an example (as has Stroustrup) where this is ok.


    As you can see, it is not OK. A Vector is *not* a std::vector<int>.
    Vector adapts the behaviour of std::vector<int>, so it can't be used as
    one unless it restricts the public interface.

    --
    Ian Collins
    Ian Collins, Mar 3, 2010
    #6
  7. Alf P. Steinbach

    Ian Collins Guest

    Leigh Johnston wrote:
    >
    > Or to put it another way the "is-a" relationship holds true as modifying
    > a Vector object via the std::vector interface does not invalidate
    > Vector's invariant.


    It does:

    vec.at(1) = 33;

    std::cout << vec[1] << std::endl;

    --
    Ian Collins
    Ian Collins, Mar 3, 2010
    #7
  8. Alf P. Steinbach

    Ian Collins Guest

    Leigh Johnston wrote:
    >
    >
    > "Ian Collins" <> wrote in message
    > news:...
    >> Leigh Johnston wrote:
    >>>
    >>> Or to put it another way the "is-a" relationship holds true as
    >>> modifying a Vector object via the std::vector interface does not
    >>> invalidate Vector's invariant.

    >>
    >> It does:
    >>
    >> vec.at(1) = 33;
    >>
    >> std::cout << vec[1] << std::endl;

    >
    > Vector as it stands does not make much sense and should also provide an
    > at() but even then you cannot do a straight substitution is parameter
    > values would have different meanings so it is not a particularly good
    > example I admit, however "is-a" still holds, you can pass a reference to
    > a Vector to a function which takes a std::vector reference and it still
    > works.


    I agree. I had overlooked Vector's operator[] hiding rather than
    overloading std::vector's.

    It's nice to see a reasoned response without expletives and personal
    insults :)

    --
    Ian Collins
    Ian Collins, Mar 3, 2010
    #8
  9. > >>> Maybe "avoid deriving publicly form concrete classes" would be better
    > >>> advice?  It certainly applies to standard containers.

    >
    > > A counter example doesn't negate a general guideline.  There will always
    > > be cases where a guideline doesn't apply because a guideline is only a
    > > recommendation, not a rule.  I would use private derivation for the
    > > example in TC++PL, the interface class is changing the behaviour of
    > > std::vector, so it should only expose interfaces that comply with the
    > > change (consider what would happen if the user mixed at() with [] access).

    >
    > > I still maintain that "avoid deriving publicly from concrete classes" is a
    > > valid guideline.  Any advice that saves the novice unnecessary grief
    > > should be welcome and I've seen nasty bugs caused by improper use of
    > > pointers to concrete base classes.

    >
    > I am sorry but this is just absolute garbage; there is absolutely nothing
    > wrong with deriving publicly or otherwise from concrete classes.  The
    > standard containers are not designed to be derived from if you consider that
    > they do not have a virtual destructor but I have given an example (as has
    > Stroustrup) where this is ok.
    >
    > The "is-a" relationship does not dictate that base classes must be abstract
    > and a so called guideline which dictates otherwise is simply ill conceived
    > bullshit.  Just because you have seen "nasty bugs" is mostly irrelevant..
    > This newsgroup really does contain some drivel to which you have just added
    > to.
    >
    > /Leigh


    Quick note of agreement. I'm all-too-regularly dismayed at how much
    time and effort some people spend either writing half-baked containers
    or using STL containers in an awkward, verbose and/or error-prone
    fashion simply because they'd read or been told they shouldn't derive
    from them to customise the interface to intended usage. Avoiding
    customisation typically introduces far more bugs and confusion,
    lowering productivity and flexibility. The number of times I've seen
    someone proceed to allocate a derived object on the heap and free it
    through a base-class pointer is minute in comparison.

    Guidelines can be good, but it's important to do things simply and
    directly where it works. Similar issues with struct + public data vs
    classes + accessor functions: you only bother with the latter where
    it's useful, shared across files etc.. Or providing function
    implementation out of line. Lots of little things like this, taking
    experience to know where to draw the line. A "safe" guideline for
    beginners isn't necessarily safer if it forces those beginners to use
    a long-winded and more confusing workaround to achieve the same
    functionality....

    Cheers,
    Tony
    Anthony Delroy, Mar 4, 2010
    #9
  10. On 3 mar, 21:10, "Alf P. Steinbach" <> wrote:
    > * Leigh Johnston:
    >
    > > Warning: contact with this newsgroup can result in exposure to toxic
    > > opinions the treatment of which involves the use of copious amounts of
    > > thinking for yourself.

    >
    > :)
    >
    > IMHO you're absolutely right  --  but it applies to any newsgroup!
    >
    > On the other hand, ..., well, wait, I'm not opening that can.
    >
    > But on the third and gripping hand, while the opinion that I think triggered
    > that blast, "don't derive from concrete classes", may not be the world's best
    > advice, it is a practice that works for some kinds of problems. For example,
    > original COM was built on something very similar to that idea, "don't expose
    > derivation from concrete classes to client code". But I think that even that
    > more limited idea was shown to be too drastic, when COM+ did away with it.. :)


    IMHO "don't derive from concrete class" is a poor wording. I prefer
    "inherit an interface, not an implementation" (IIRC adapted from
    Gamma&GoF).

    IMNSHO inheriting from a concrete class is perfectly valid when you
    only want to add to the interface of an object - after all, it is part
    of the 3 fundamental OOP rules.

    --
    Michael
    Michael Doubez, Mar 4, 2010
    #10
  11. On 4 mar, 11:42, "Leigh Johnston" <> wrote:
    > "Michael Doubez" <> wrote in message
    >
    > news:...
    >
    >
    >
    > > On 3 mar, 21:10, "Alf P. Steinbach" <> wrote:
    > >> * Leigh Johnston:

    >
    > >> > Warning: contact with this newsgroup can result in exposure to toxic
    > >> > opinions the treatment of which involves the use of copious amounts of
    > >> > thinking for yourself.

    >
    > >> :)

    >
    > >> IMHO you're absolutely right  --  but it applies to any newsgroup!

    >
    > >> On the other hand, ..., well, wait, I'm not opening that can.

    >
    > >> But on the third and gripping hand, while the opinion that I think
    > >> triggered
    > >> that blast, "don't derive from concrete classes", may not be the world's
    > >> best
    > >> advice, it is a practice that works for some kinds of problems. For
    > >> example,
    > >> original COM was built on something very similar to that idea, "don't
    > >> expose
    > >> derivation from concrete classes to client code". But I think that even
    > >> that
    > >> more limited idea was shown to be too drastic, when COM+ did away with
    > >> it. :)

    >
    > > IMHO "don't derive from concrete class" is a poor wording. I prefer
    > > "inherit an interface, not an implementation" (IIRC adapted from
    > > Gamma&GoF).

    >
    > > IMNSHO inheriting from a concrete class is perfectly valid when you
    > > only want to add to the interface of an object - after all, it is part
    > > of the 3 fundamental OOP rules.

    >
    > Inheriting from a concrete class to provide additional state and/or logic is
    > also fine.  Inheritance is fine, period.


    Other languages felt the need to distinguish between "extends" and
    "implements"
    or between "class" and "interface" (and add some constraints along
    the way). Inheritance in C++ (which fulfill both roles) is not as
    straightforward.

    In this regard, IMO C++ inherited from C's way of thinking "let the
    programmer be in control"; and it is the programmer's responsibility
    to enforce the design is correct.

    --
    Michael
    Michael Doubez, Mar 4, 2010
    #11
  12. Alf P. Steinbach

    James Kanze Guest

    On Mar 3, 9:09 pm, Ian Collins <> wrote:
    > Alf P. Steinbach wrote:


    [...]
    > > But on the third and gripping hand, while the opinion that I
    > > think triggered that blast, "don't derive from concrete
    > > classes", may not be the world's best advice, it is a
    > > practice that works for some kinds of problems.


    > Maybe "avoid deriving publicly form concrete classes" would be
    > better advice? It certainly applies to standard containers.


    I don't know. I haven't seen the thread that goes into that
    topic in detail---I rather thought the reaction concerned not
    making virtual functions public. But whatever: a fairly long
    time ago, Scott Meyers recommended not deriving from concrete
    classes, or at least, not deriving from classes with data
    members. Because of the problems correctly implementing
    assignment, I think. In practice, on the other hand, the
    template method pattern will often require derivation from a
    class with data members, and it's a fairly well established
    pattern. And since we've since more or less learned that
    assignment and polymorphism don't mix well, classes using the
    template method pattern will normally block assignment, rather
    than try to implement it.

    At any rate, I don't really think of it as a general rule,
    although except when using the template method pattern, it's not
    something that you'd probably want to do too often. (Note too
    that it's been a while since I've heard anyone argue for this
    rule. I don't know what Scott's position concerning it is
    today.)

    --
    James Kanze
    James Kanze, Mar 4, 2010
    #12
  13. Alf P. Steinbach

    James Kanze Guest

    On Mar 4, 8:32 am, Michael Doubez <> wrote:
    > On 3 mar, 21:10, "Alf P. Steinbach" <> wrote:
    > > * Leigh Johnston:


    > IMHO "don't derive from concrete class" is a poor wording. I prefer
    > "inherit an interface, not an implementation" (IIRC adapted from
    > Gamma&GoF).


    > IMNSHO inheriting from a concrete class is perfectly valid
    > when you only want to add to the interface of an object -
    > after all, it is part of the 3 fundamental OOP rules.


    Before arguing against the rule, it would be interesting to see
    who is proposing it, and why. To date, the only thing I've seen
    recently is a mention that Herb Sutter cites it. Until I've
    seen why it's being recommended, I can't really argue one way or
    the other. (I haven't actuall seen anyone propose it since
    about 1995, but I haven't seen everything. Still, I would like
    to know what is wrong with something like:

    class TemplateBase
    {
    private:
    virtual void customizationFunction();
    // with a default implemenation
    };

    A class using the template method pattern for customization,
    but which provides defaults for all of the customization, seems
    like a classical example of a case where a concrete class is
    actuall designed to be used as a base class (with public
    inheritance).

    Deriving from classes which weren't designed to be bases (such
    as the standard containers) is generally a bad idea. But the
    key to whether you should derive from a class or not isn't
    whether it is concrete or not; it's whether it was designed to
    be used as a base class or not.

    --
    James Kanze
    James Kanze, Mar 4, 2010
    #13
  14. On 4 mar, 19:37, James Kanze <> wrote:
    > On Mar 4, 8:32 am, Michael Doubez <> wrote:
    >
    > > On 3 mar, 21:10, "Alf P. Steinbach" <> wrote:
    > > > * Leigh Johnston:

    > > IMHO "don't derive from concrete class" is a poor wording. I prefer
    > > "inherit an interface, not an implementation" (IIRC adapted from
    > > Gamma&GoF).
    > > IMNSHO inheriting from a concrete class is perfectly valid
    > > when you only want to add to the interface of an object -
    > > after all, it is part of the 3 fundamental OOP rules.

    >
    > Before arguing against the rule, it would be interesting to see
    > who is proposing it, and why.


    I cannot remember who stated them, it dates to my academics:
    "A computer language is object-oriented if they support the three
    fundamental features: polymorphism, inheritance, and encapsulation."

    Inheritance in the OOP sense, i.e. (arguably) to reuse a class
    implementation in order to *add* to its interface (not modifying its
    internals, that's polymorphism).

    >  To date, the only thing I've seen
    > recently is a mention that Herb Sutter cites it.  Until I've
    > seen why it's being recommended, I can't really argue one way or
    > the other.  (I haven't actuall seen anyone propose it since
    > about 1995, but I haven't seen everything.  Still, I would like
    > to know what is wrong with something like:
    >
    >         class TemplateBase
    >         {
    >         private:
    >                 virtual void customizationFunction();
    >                                         // with a default implemenation
    >         };
    >
    > A class using the template method pattern for customization,
    > but which provides defaults for all of the customization, seems
    > like a classical example of a case where a concrete class is
    > actuall designed to be used as a base class (with public
    > inheritance).


    IMHO, part of the misunderstanding stems from the fact that in C++,
    polymorphism is /usually/ performed through inheritance.

    As a consequence, in C++ a class can inherit from another for both
    reasons: reusing code (of the base classe) and create a polymorphic
    implementation.

    Whether it is a good thing or not is IMO what is (should be) debated
    here; should a virtual function from a base class be implemented ?
    Separating the concern, with your example we could write:

    class TemplateBaseIsPolymorphic
    {
    private:
    virtual void customizationFunction()=0;
    };

    class TemplateBase: TemplateBaseIsPolymorphic
    {
    private:
    virtual void customizationFunction()
    {
    // default implementation
    }
    };

    From the C++ language point of view, this doesn't add a lot and
    personally I prefer the original example.

    > Deriving from classes which weren't designed to be bases (such
    > as the standard containers) is generally a bad idea.


    That's because, IMO the standard containers usually have a complete
    interface and there is no need to.

    > But the
    > key to whether you should derive from a class or not isn't
    > whether it is concrete or not; it's whether it was designed to
    > be used as a base class or not.


    My point exactly.

    --
    Michael
    Michael Doubez, Mar 5, 2010
    #14
  15. Alf P. Steinbach

    James Kanze Guest

    On 5 Mar, 09:26, Michael Doubez <> wrote:
    > On 4 mar, 19:37, James Kanze <> wrote:
    > > On Mar 4, 8:32 am, Michael Doubez <> wrote:


    > > > On 3 mar, 21:10, "Alf P. Steinbach" <> wrote:
    > > > > * Leigh Johnston:
    > > > IMHO "don't derive from concrete class" is a poor wording.
    > > > I prefer "inherit an interface, not an implementation"
    > > > (IIRC adapted from Gamma&GoF).
    > > > IMNSHO inheriting from a concrete class is perfectly valid
    > > > when you only want to add to the interface of an object -
    > > > after all, it is part of the 3 fundamental OOP rules.


    > > Before arguing against the rule, it would be interesting to
    > > see who is proposing it, and why.


    > I cannot remember who stated them, it dates to my academics:
    > "A computer language is object-oriented if they support the
    > three fundamental features: polymorphism, inheritance, and
    > encapsulation."


    Which doesn't really address the question: C++ does support
    those three fundamental features, so it is object-oriented.
    (But it's not only object-oriented; it supports other things as
    well.) And those three features say nothing about deriving from
    a concrete class---the template method pattern was frequent long
    before the GoF named it; as far as I know, it was always
    considered good OO practice. And if the base class in the
    template method pattern provides a default implementation, it is
    concrete.

    > Inheritance in the OOP sense, i.e. (arguably) to reuse a class
    > implementation in order to *add* to its interface (not
    > modifying its internals, that's polymorphism).


    > > To date, the only thing I've seen recently is a mention that
    > > Herb Sutter cites it. Until I've seen why it's being
    > > recommended, I can't really argue one way or the other. (I
    > > haven't actuall seen anyone propose it since about 1995, but
    > > I haven't seen everything. Still, I would like to know what
    > > is wrong with something like:


    > > class TemplateBase
    > > {
    > > private:
    > > virtual void customizationFunction();
    > > // with a default implemenation
    > > };


    > > A class using the template method pattern for customization,
    > > but which provides defaults for all of the customization,
    > > seems like a classical example of a case where a concrete
    > > class is actuall designed to be used as a base class (with
    > > public inheritance).


    > IMHO, part of the misunderstanding stems from the fact that in
    > C++, polymorphism is /usually/ performed through inheritance.


    As it is in many modern OO languages. Static typing isn't
    without advantages.

    > As a consequence, in C++ a class can inherit from another for
    > both reasons: reusing code (of the base classe) and create a
    > polymorphic implementation.


    > Whether it is a good thing or not is IMO what is (should be)
    > debated here; should a virtual function from a base class be
    > implemented ? Separating the concern, with your example we
    > could write:


    > class TemplateBaseIsPolymorphic
    > {
    > private:
    > virtual void customizationFunction()=0;
    >
    > };


    > class TemplateBase: TemplateBaseIsPolymorphic
    > {
    > private:
    > virtual void customizationFunction()
    > {
    > // default implementation
    >
    > }
    > };


    > From the C++ language point of view, this doesn't add a lot
    > and personally I prefer the original example.


    Yes. Separation of concerns is a good principle, but there are
    times that it can be taken too far. (Actually, which of the
    above is preferrable depends on the context. What if it were:

    class TemplateBase
    {
    virtual void customizationFunction() = 0;
    };

    class DefaultTemplate : public TemplateBase
    {
    virtual void customizationFunction()
    {
    // default implementation...
    }
    };

    ..)

    > > Deriving from classes which weren't designed to be bases
    > > (such as the standard containers) is generally a bad idea.


    > That's because, IMO the standard containers usually have a
    > complete interface and there is no need to.


    Also, maybe. But my rule holds: deriving from a class which was
    not designed to be used as a base will generally cause problems
    in the long run, and should generall be avoided. (There are
    exceptions, and I have no problems with people deriving in order
    to provide a few special constructors; e.g. to create a fully
    filled const vector.)

    --
    James Kanze
    James Kanze, Mar 5, 2010
    #15
  16. On 5 mar, 11:25, "Leigh Johnston" <> wrote:
    > "Michael Doubez" <> wrote in message
    > news:...
    > > On 4 mar, 19:37, James Kanze <> wrote:

    [snip]
    > >> Deriving from classes which weren't designed to be bases (such
    > >> as the standard containers) is generally a bad idea.

    >
    > > That's because, IMO the standard containers usually have a complete
    > > interface and there is no need to.

    >
    > The examples I gave where for the case where an interface needs to be
    > augmented but you use the word "usually" which is fine: "usually" is not
    > "always".


    But the corollary is that is seldom useful or a good design decision
    to inherit from them. A complete interface means that functions or
    composition should be used; AFAIS there are three cases:
    - the extended part is stateless: a function should be used
    - the extended part keeps associated state:
    * the extended class should be somewhat notified of modification
    but the base class is not designed that way and composition should be
    used (I exclude an external notify modification system)
    * the extended class doesn't need to be notified, both
    information should be composed as a pair in another structure
    * the extended structure exploits the internal of the container:
    this is not portable, even across the same version of the compiler.

    I don't say that such cases never *exists*, but IMHO they should
    require an exceptionally good justification (such as "can't do it
    another way and it will be strongly encapsulated").

    > >> But the
    > >> key to whether you should derive from a class or not isn't
    > >> whether it is concrete or not; it's whether it was designed to
    > >> be used as a base class or not.

    >
    > > My point exactly.

    >
    > A class does not have to be abstract to be usable as a base class.


    It doesn't but it is IMO a very narrow usage of inheritance in C++; I
    can't see I have never seen it (or done it).

    But, one strives to provide a complete interface without compromising
    encapsulation, doesn't he.

    --
    Michael
    Michael Doubez, Mar 8, 2010
    #16
  17. On 5 mar, 14:19, Juha Nieminen <> wrote:
    > Michael Doubez wrote:
    > > Inheritance in the OOP sense, i.e. (arguably) to reuse a class
    > > implementation in order to *add* to its interface (not modifying its
    > > internals, that's polymorphism).

    >
    >   One could say that there are two schools of thought about inheritance:
    > The "extends" faction and the "specializes" faction (although they are
    > not necessarily mutually exclusive). There's a subtle difference between
    > the two ways of thinking about inheritance.
    >
    >   In the "extends" school of thought inheritance is seen as taking a
    > class and adding more functionality to it. It's also related to code
    > reuse: If two classes have common functionality, the common
    > functionality can be grouped into a common base class, and then the two
    > classes can inherit from it (so, in effect, the two classes are now
    > extending the base class functionality in two different ways, while
    > having the common functionality in one place, thus avoiding code
    > repetition). Thus when you inherit you could say "DerivedClass extends
    > BaseClass".
    >
    >   The "specializes" school of thought is more related to object-oriented
    > design. This is where the concept of the "is-a" relationship comes from.
    > Here a class is a concept, and there's a scale of abstraction between
    > concepts: Some concepts are more abstract and generic, while others are
    > more concrete and specialized. For example, in a GUI framework you could
    > have a class named "Widget", and several classes derived from it, eg.
    > "Button" and "Label". In this case "Widget" is a more generic and
    > abstract concept, while "Button" and "Label" are more concrete concepts.
    > In other words, they are Widget specializations. Thus one can say that
    > "Button is-a Widget" and "Label is-a Widget". However, Button is *not* a
    > Label. What this means in practice is that wherever an object of type
    > Widget is expected, an object of type Button or Label can be given
    > instead (because a Button *is* a Widget, as well as a Label *is* a
    > Widget). However, if a Button is expected, a Label cannot given to it
    > (because a Label is *not* a Button). Thus when you inherit you could say
    > "DerivedClass specializes BaseClass" (ie. creates a more concrete
    > concept from it).
    >
    >   The "specializes" school of thought is not mutually exclusive with the
    > "extends" one. One could say that the latter is just a side-effect of
    > the former, and could be used (or "abused") for that purpose.


    I hear what you say but I have a gut feeling that the is-a/has-a
    system is very good for tuition of concept thinking but rarely scale
    in practice.
    When people think of is-a, they tend to speak about polymorphism -
    i.e. the object should respond to a given interface.
    We can see the failing in the case of the circle which is an ellipsis
    but doesn't share the interface. We you say an animal is-a mammal, you
    expect him to have some attributes not to respond to an archetypal
    mammal form.
    In the end, you have to determine the minimal interface that doesn't
    break LSP.
    In don't say it doesn't work (it certainly work in Small-Talk), it is
    just that it doesn't scale so well (even in small talk, there is an
    extensive usage of the fallback function).

    IMHO the concept system should be orthogonal with inheritance (as it
    is with standard containers) and perhaps relabel is-a into act-as.

    Taking the GUI framework example, IMO "Widget" is another word for
    "Stuff that belong to the framework"; which is kin to "lets give use a
    base class to manipulate them generically". Which means that, as I see
    it, a widget is an interface to polymorphic behavior.

    I have in mind a badly designed GUI library (fltk IIRC) where
    everything had been put into the /Widget/ base class (the actions
    callback, the label ...) and subclasses used them or not depending on
    the specialization.

    --
    Michael
    Michael Doubez, Mar 8, 2010
    #17
  18. On 8 mar, 12:01, "Leigh Johnston" <> wrote:
    > "Michael Doubez" <> wrote in message
    >
    > news:...
    >
    >
    >
    > > On 5 mar, 11:25, "Leigh Johnston" <> wrote:
    > >> "Michael Doubez" <> wrote in message
    > >>news:....
    > >> > On 4 mar, 19:37, James Kanze <> wrote:

    > > [snip]
    > >> >> Deriving from classes which weren't designed to be bases (such
    > >> >> as the standard containers) is generally a bad idea.

    >
    > >> > That's because, IMO the standard containers usually have a complete
    > >> > interface and there is no need to.

    >
    > >> The examples I gave where for the case where an interface needs to be
    > >> augmented but you use the word "usually" which is fine: "usually" is not
    > >> "always".

    >
    > > But the corollary is that is seldom useful or a good design decision
    > > to inherit from them. A complete interface means that functions or
    > > composition should be used; AFAIS there are three cases:
    > >  - the extended part is stateless: a function should be used
    > >  - the extended part keeps associated state:
    > >     * the extended class should be somewhat notified of modification
    > > but the base class is not designed that way and composition should be
    > > used (I exclude an external notify modification system)
    > >     * the extended class doesn't need to be notified, both
    > > information should be composed as a pair in another structure
    > >     * the extended structure exploits the internal of the container:
    > > this is not portable, even across the same version of the compiler.

    >
    > Garbage.


    Really ?
    A minimal complete interface is IMO an essential value for general
    purpose class design (I am not talking about classes implementing
    specific use cases).

    > The "is-a" relationship is well defined


    I am curious to hear your definition.

    > and perfectly fine.


    I find it ambiguous: it depends on what you mean by "is".

    In fact, I find it useful only in defining what is-not (i.e. what
    should be composed and not inherited).

    > [snip]


    --
    Michael
    Michael Doubez, Mar 8, 2010
    #18
  19. On 8 mar, 13:48, "Leigh Johnston" <> wrote:
    > "Michael Doubez" <> wrote in message
    >
    > news:...
    >
    >
    >
    > > On 8 mar, 12:01, "Leigh Johnston" <> wrote:
    > >> "Michael Doubez" <> wrote in message

    >
    > >>news:....

    >
    > >> > On 5 mar, 11:25, "Leigh Johnston" <> wrote:
    > >> >> "Michael Doubez" <> wrote in message
    > >> >>news:...
    > >> >> > On 4 mar, 19:37, James Kanze <> wrote:
    > >> > [snip]
    > >> >> >> Deriving from classes which weren't designed to be bases (such
    > >> >> >> as the standard containers) is generally a bad idea.

    >
    > >> >> > That's because, IMO the standard containers usually have a complete
    > >> >> > interface and there is no need to.

    >
    > >> >> The examples I gave where for the case where an interface needs to be
    > >> >> augmented but you use the word "usually" which is fine: "usually" is
    > >> >> not
    > >> >> "always".

    >
    > >> > But the corollary is that is seldom useful or a good design decision
    > >> > to inherit from them. A complete interface means that functions or
    > >> > composition should be used; AFAIS there are three cases:
    > >> >  - the extended part is stateless: a function should be used
    > >> >  - the extended part keeps associated state:
    > >> >     * the extended class should be somewhat notified of modification
    > >> > but the base class is not designed that way and composition should be
    > >> > used (I exclude an external notify modification system)
    > >> >     * the extended class doesn't need to be notified, both
    > >> > information should be composed as a pair in another structure
    > >> >     * the extended structure exploits the internal of the container:
    > >> > this is not portable, even across the same version of the compiler.

    >
    > >> Garbage.

    >
    > > Really ?
    > > A minimal complete interface is IMO an essential value for general
    > > purpose class design (I am not talking about classes implementing
    > > specific use cases).

    >
    > >> The "is-a" relationship is well defined

    >
    > > I am curious to hear your definition.

    >
    > >> and perfectly fine.

    >
    > > I find it ambiguous: it depends on what you mean by "is".

    >
    > > In fact, I find it useful only in defining what is-not (i.e. what
    > > should be composed and not inherited).

    >
    > Example of "is-a":
    >
    > struct widget
    > {
    >   colour background;
    >   virtual void draw(device_context& dc) const
    >   {
    >     dc.fill_rect(client_rect(), background);
    >   }
    >   colour get_background() const { return background; }
    >
    > };
    >
    > struct label : widget
    > {
    >   virtual void draw(device_context& dc) const
    >   {
    >     widget::draw(dc); // erases background in background colour
    >     dc.draw_text(0, 0, get_background() ^ -1, label_text()); // draw text in
    > inverted colour
    >   }
    > };
    >
    > label "is-a" widget, i.e. it inherits a widget's ability to fill in its
    > background and this behaviour is optional (label does not have to call
    > widget::draw()).  label also inherits widget's background colour and can
    > query it for use in its own drawing code.


    If I have a Spacer widget that doesn't draw anything, the background
    member is useless.

    And the name widget (WIndow gaDGET) is not really a thing, it is more
    a base class for elements contained within a window. To me, it looks
    like something you are forced into by strong typing rather than a
    design decision.

    > "is-a" is related to LSP:
    >
    > struct window
    > {
    >   std::vector<widget*> widgets;
    >   device_context dc;
    >   void draw()
    >   {
    >     for (auto i = widgets.begin(); i != widgets.end(); ++i)
    >       i->draw(dc);
    >   }
    > }
    >
    > i.e. if LSP is adhered to then a label can be passed to any function which
    > accepts a widget reference/pointer.  This is the essence of the "is-a"
    > relationship.


    Well, is-a yields a correct program only if it preserves LSP. Although
    there are some cases where LSP is not preserved: if I make Integer and
    String subtypes of AdditiveType, Integer addition is symmetric but
    String addition/concatenation is not although math tells us that '+'
    is reserved for symmetric operations.

    From the examples you gave, I see that, for you, is-a is thought in
    terms of interface and polymorphism, not in terms of subtyping.

    Now, if I have a class Mammal:
    class Mammal
    {
    public:
    Mammal(unsigned nb_breast):nb_breast(nb_breast){}

    unsigned nbBreast()const{ return nb_breast; };
    protected:
    unsigned nb_breast;
    };

    If I define cat is-a mammal:
    class Cat: public Mammal
    {
    public:
    enum Type{ /* type of cat */};

    Cat(Type type): Mammal(catType2NbBreast(type)){}

    void mastectomy(unsigned nb_breast_removed)
    {
    assert( nb_breast_removed <= nb_breast);
    nb_breast -= nb_breast_removed;
    }
    };

    Here, I have a is-a relationship without talking about LSP or
    polymorphism.

    As I said elsewhere, the fact that C++ implements (dynamic)
    polymorphism in terms of inheritance doesn't help. Well, it couldn't
    do it another way, now, could it ?

    --
    Michael
    Michael Doubez, Mar 8, 2010
    #19
  20. On 8 mar, 15:49, "Leigh Johnston" <> wrote:
    > "Michael Doubez" <> wrote in message
    >
    > news:...
    >
    >
    >
    > > On 8 mar, 13:48, "Leigh Johnston" <> wrote:
    > >> "Michael Doubez" <> wrote in message

    >
    > >>news:....

    >
    > >> > On 8 mar, 12:01, "Leigh Johnston" <> wrote:
    > >> >> "Michael Doubez" <> wrote in message

    >
    > >> >>news:...

    >
    > >> >> > On 5 mar, 11:25, "Leigh Johnston" <> wrote:
    > >> >> >> "Michael Doubez" <> wrote in message
    > >> >> >>news:...
    > >> >> >> > On 4 mar, 19:37, James Kanze <> wrote:
    > >> >> > [snip]
    > >> >> >> >> Deriving from classes which weren't designed to be bases (such
    > >> >> >> >> as the standard containers) is generally a bad idea.

    >
    > >> >> >> > That's because, IMO the standard containers usually have a
    > >> >> >> > complete
    > >> >> >> > interface and there is no need to.

    >
    > >> >> >> The examples I gave where for the case where an interface needs to
    > >> >> >> be
    > >> >> >> augmented but you use the word "usually" which is fine: "usually"
    > >> >> >> is
    > >> >> >> not
    > >> >> >> "always".

    >
    > >> >> > But the corollary is that is seldom useful or a good design decision
    > >> >> > to inherit from them. A complete interface means that functions or
    > >> >> > composition should be used; AFAIS there are three cases:
    > >> >> >  - the extended part is stateless: a function should be used
    > >> >> >  - the extended part keeps associated state:
    > >> >> >     * the extended class should be somewhat notified of modification
    > >> >> > but the base class is not designed that way and composition should
    > >> >> > be
    > >> >> > used (I exclude an external notify modification system)
    > >> >> >     * the extended class doesn't need to be notified, both
    > >> >> > information should be composed as a pair in another structure
    > >> >> >     * the extended structure exploits the internal of the container:
    > >> >> > this is not portable, even across the same version of the compiler.

    >
    > >> >> Garbage.

    >
    > >> > Really ?
    > >> > A minimal complete interface is IMO an essential value for general
    > >> > purpose class design (I am not talking about classes implementing
    > >> > specific use cases).

    >
    > >> >> The "is-a" relationship is well defined

    >
    > >> > I am curious to hear your definition.

    >
    > >> >> and perfectly fine.

    >
    > >> > I find it ambiguous: it depends on what you mean by "is".

    >
    > >> > In fact, I find it useful only in defining what is-not (i.e. what
    > >> > should be composed and not inherited).

    >
    > >> Example of "is-a":

    >
    > >> struct widget
    > >> {
    > >>   colour background;
    > >>   virtual void draw(device_context& dc) const
    > >>   {
    > >>     dc.fill_rect(client_rect(), background);
    > >>   }
    > >>   colour get_background() const { return background; }

    >
    > >> };

    >
    > >> struct label : widget
    > >> {
    > >>   virtual void draw(device_context& dc) const
    > >>   {
    > >>     widget::draw(dc); // erases background in background colour
    > >>     dc.draw_text(0, 0, get_background() ^ -1, label_text()); // draw text
    > >> in
    > >> inverted colour
    > >>   }
    > >> };

    >
    > >> label "is-a" widget, i.e. it inherits a widget's ability to fill in its
    > >> background and this behaviour is optional (label does not have to call
    > >> widget::draw()).  label also inherits widget's background colour and can
    > >> query it for use in its own drawing code.

    >
    > > If I have a Spacer widget that doesn't draw anything, the background
    > > member is useless.

    >
    > > And the name widget (WIndow gaDGET) is not really a thing, it is more
    > > a base class for elements contained within a window. To me, it looks
    > > like something you are forced into by strong typing rather than a
    > > design decision.

    >
    > >> "is-a" is related to LSP:

    >
    > >> struct window
    > >> {
    > >>   std::vector<widget*> widgets;
    > >>   device_context dc;
    > >>   void draw()
    > >>   {
    > >>     for (auto i = widgets.begin(); i != widgets.end(); ++i)
    > >>       i->draw(dc);
    > >>   }
    > >> }

    >
    > >> i.e. if LSP is adhered to then a label can be passed to any function
    > >> which
    > >> accepts a widget reference/pointer.  This is the essence of the "is-a"
    > >> relationship.

    >
    > > Well, is-a yields a correct program only if it preserves LSP. Although
    > > there are some cases where LSP is not preserved: if I make Integer and
    > > String subtypes of AdditiveType, Integer addition is symmetric but
    > > String addition/concatenation is not although math tells us that '+'
    > > is reserved for symmetric operations.

    >
    > > From the examples you gave, I see that, for you, is-a is thought in
    > > terms of interface and polymorphism, not in terms of subtyping.

    >
    > > Now, if I have a class Mammal:
    > > class Mammal
    > > {
    > >  public:
    > >    Mammal(unsigned nb_breast):nb_breast(nb_breast){}

    >
    > >    unsigned nbBreast()const{ return nb_breast; };
    > >  protected:
    > >     unsigned nb_breast;
    > > };

    >
    > > If I define cat is-a mammal:
    > > class Cat: public Mammal
    > > {
    > >  public:
    > >  enum Type{ /* type of cat */};

    >
    > >  Cat(Type type): Mammal(catType2NbBreast(type)){}

    >
    > >  void mastectomy(unsigned nb_breast_removed)
    > >  {
    > >   assert( nb_breast_removed <= nb_breast);
    > >   nb_breast -= nb_breast_removed;
    > >  }
    > > };

    >
    > > Here, I have a is-a relationship without talking about LSP or
    > > polymorphism.

    >
    > > As I said elsewhere, the fact that C++ implements (dynamic)
    > > polymorphism in terms of inheritance doesn't help. Well, it couldn't
    > > do it another way, now, could it ?

    >
    > Your example is just an example of ordinary derivation, I use derivation for
    > non-polymorphic classes also.  Both the "is-a" relationship and LSP do not
    > require polymorphism to be valid I never said they did, I just happened to
    > give an example which was polymorphic.


    LSP does concern polymorphism otherwise it is useless. I merely gave
    an example of is-a relationship without polymorphism to show LSP is
    not part of "the essence of 'is-a' relationship".

    > "is-a" relationship holds true if LSP holds true.  Your example does not
    > violate LSP, I can pass a Cat to a function requiring an Mammal reference
    > and calling the nbBreast() member function will work.


    Yes but LSP is not involved in any way in my example.

    I think we have lost the trail of the discussion somewhere. My claim
    was that is-a relationship is ambiguous and is usually assimilated to
    polymorphism - which it is not.

    And you are proving me right: the first example you give is pure
    polymorphic behavior and you define it in relation to LSP.

    Unless you are claiming that a is-a relationship is necessarily
    polymorphic; in which case I will ask: isn't my example a is-a
    relationship ?

    --
    Michael
    Michael Doubez, Mar 8, 2010
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mike Treseler

    Re: Quartus warning in NUMERIC_STD.vhd

    Mike Treseler, Jul 11, 2003, in forum: VHDL
    Replies:
    2
    Views:
    1,843
    Clyde R. Shappee
    Jul 13, 2003
  2. Pete Becker
    Replies:
    0
    Views:
    1,373
    Pete Becker
    Feb 10, 2005
  3. B. Williams

    warning C4267 and warning C4996

    B. Williams, Oct 26, 2006, in forum: C++
    Replies:
    17
    Views:
    2,627
  4. WARNING! Prosoftstore.com is a SCAM! WARNING!

    , Jul 8, 2007, in forum: ASP .Net Web Services
    Replies:
    0
    Views:
    314
  5. Julian Mehnle
    Replies:
    17
    Views:
    866
    Julian Mehnle
    May 18, 2006
Loading...

Share This Page