Re: Warning
"Michael Doubez" <michael.doubez@free.fr> wrote in message
news:bffc3535-8ad3-4816-b3cf-83f72c78e556@j27g2000yqn.googlegroups.com...
On 8 mar, 12:01, "Leigh Johnston" <le...@i42.co.uk> wrote:
"Michael Doubez" <michael.dou...@free.fr> wrote in message
news:d962d8ed-d69e-4b5f-a224-bebd8dcafb83@e7g2000yqf.googlegroups.com...
On 5 mar, 11:25, "Leigh Johnston" <le...@i42.co.uk> wrote:
"Michael Doubez" <michael.dou...@free.fr> wrote in message
news:cdb20f88-8668-4092-972e-85a119dff724@j27g2000yqn.googlegroups.com...
On 4 mar, 19:37, James Kanze <james.ka...@gmail.com> 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
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.
"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.
/Leigh