Topic: Q: virtual functions not overridable anymore?


Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/01
Raw View
[Colin : this article is the corrected version of the last
one, which containned an error. I hope it's clearer.]

Colin Rafferty <craffert@ml.com> writes:

> Valentin Bonnard writes:
> > Valentin Bonnard <bonnardv@pratique.fr> writes:
> >> Colin Rafferty <craffert@ml.com> writes:
> >> > Michael B Taylor writes:

> >> > > the desire to declare a virtual method "final" in some derived
> >> > > class is the same as the desire to declare a method in a class
> >> > > non-virtual.

I think so.

> > Let's say you have the following GUI classes:
>
> > class Window {
> >     virtual void draw () = 0;
> > };
>
> > class Dialog {
> >     void draw ()
> >     {
> >         for_each (items.begin (), items.end (),
> >                   ptr_mem_fun (DialogItem::draw));
> >     }
> >     list<DialogItem> items;
> > };
>
> > class DialogItem {
> >     virtual void draw () = 0;
> > };
>
> > You might want to declare Dialog::draw () final as at this point,
> > behaviour should be changed by deriving from DialogItem, not Dialog.
>
> If I want to decorate Dialog, I would have to subclass from it, and draw
> myself.  Of course, I have to keep the old behavior as well.  But I want
> to extend it.
>
> class ModalDialog
                  : public Dialog {
>     void draw ()
>     {
>         // do something modal...
>         Dialog::draw();
>         // do something else modal...
>     }
> };
>
> > In particular, any member of Dialog can assume that Dialog::draw
> > as the same effect as Dialog::draw (), the same undocumented
> > semantics...
>
> Which means that any subclass of Dialog is responsible for doing the
> appropriate thing.  Usually, this means calling the base class's
> implementation.

Partly; of course, it will keep the documented and undocumented
properties of draw; for example, an undocumented property of
draw () might be that draw () calls foobar (that is, code in
Dialog may rely on that).

You are under the impression that your ModalDialog::draw ()
is correct, and that the Liskov Substitution Principle is
????

But you are doing exactly the kind of error that would be prevented
with final: as draw () should be final, it's expected that
this->draw () only does what Dialog::draw () does, so the class can
be rewritten:

class Dialog : public Window {
private:
    void dialog_draw ()
    {
        for_each (items.begin (), items.end (),
                  ptr_mem_fun (DialogItem::draw));
    }

public:
    void draw () // overrides Window::dialog_draw ()
    { dialog_draw (); }
};

for efficiency (the gain is small, but the optimisation is valid).

Then dialog_draw () will be called, and not draw (). Also,
dialog_draw () might be rewritten for a particular case:

    void dialog_draw_left ()
    {
        // items in 'items_on_the_left' are a subset of
        // items in the containner 'items'
        // I only want to draw this subset
        for_each (items_on_the_left.begin (),
                  items_on_the_left.end (),
                  ptr_mem_fun (DialogItem::draw));
    }

This function will be called instead of draw () or
dialog_draw ().

So your modal dialog will break without warning, as my
code is free to replace draw () by what it wants, and
your special code won't be called. With final, you can't
do it because I don't want you to do it.

The fact that a function is virtual is part of the interface
of a class, just as the fact that something is protected.
The decision to make a function virtual or not is an important
disign decision (which in general shouldn't be based on
performance arguments). I think that a designer should be able
to make a function final.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Mark Wilden <Mark@mWilden.com>
Date: 1997/10/02
Raw View
Valentin Bonnard wrote:
>
> Mark Wilden <Mark@mWilden.com> writes:
>
> > Valentin Bonnard wrote:
>
> > > You might want to declare Dialog::draw () final as at this point,
> > > behaviour should be changed by deriving from DialogItem, not Dialog.
> >
> > That would prevent you from doing something like this:
> >
> >  struct DebugDialog : Dialog {
> >     void draw()
> >     {
> >         cout << "About to draw dialog" << endl;
> >         Dialog::draw();
> >         cout << "Done drawing dialog" << endl;
> >     }
> >  };
>
> But any non-virtual function prevents you from doing that.

Yes, which is a good argument to why member functions should be virtual
by default. :)

> virtual functions aren't a way to patch program to remove
> bugs or to introduce debugging tests; they are a way to
> write OO programs where the derived class define a function
> the correct way.

Do you have any supporting references for that opinion? In any event, if
the derived class's purpose is to debug the parent class (perhaps
because the parent source isn't available), then my example does indeed
define the function the correct way.

I'm not saying I use derivation for debugging very often, mind you; I'm
just asking why disallow it?

> Remember: the original argument was: since we have
> non-virtual functions, we should have final functions
> (ie non-virtual functions overiding from virtual
> functions).

That's true. I was just pointing out what I saw as a flaw in the example
given, that "behaviour should be changed by deriving from DialogItem,
not Dialog." That's not necessarily true.
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/03
Raw View
Newsgroup: comp.std.c++

Mark Wilden wrote:

 > Valentin Bonnard wrote:
 > >
 > > Mark Wilden <Mark@mWilden.com> writes:
 > >
 > > > Valentin Bonnard wrote:
 > >
 > > > > You might want to declare Dialog::draw () final as at this point,
 > > > > behaviour should be changed by deriving from DialogItem, not Dialog.
 > > >
 > > > That would prevent you from doing something like this:
 > > >
 > > >  struct DebugDialog : Dialog {
 > > >     void draw()
 > > >     {
 > > >         cout << "About to draw dialog" << endl;
 > > >         Dialog::draw();
 > > >         cout << "Done drawing dialog" << endl;
 > > >     }
 > > >  };
 > >
 > > But any non-virtual function prevents you from doing that.
 >
 > Yes, which is a good argument to why member functions should be virtual
 > by default. :)

Then anyone would overide everything... but you are still limited to
members functions. Do you also want to overide non-members functions ?

It seems to me that what you want is a method to replace a function;
many compilers will let you do that by defining it in annother module.

 > > virtual functions aren't a way to patch program to remove
 > > bugs or to introduce debugging tests; they are a way to
 > > write OO programs where the derived class define a function
 > > the correct way.
 > > Do you have any supporting references for that opinion?

It seems obvious enough to me.

 > In any event, if
 > the derived class's purpose is to debug the parent class (perhaps
 > because the parent source isn't available), then my example does indeed
 > define the function the correct way.

How do you debug a class without the source ? Anyway, you have no
garanty
that the overiding function will be called except if you know completly
how the class works (that is, if you have the source).

I don't usually talk about performance to justify a design decision (as
some people draw the conclusion that, as speed isn't a problem for their
problem, the design must be innapropriate). But here, if the only
argument is about debugging, I have to say that the cost of virtual
trivial functions is very high.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Mark Wilden <Mark@mwilden.com>
Date: 1997/10/03
Raw View
Valentin Bonnard wrote:
>
> I wrote:
>  > > virtual functions aren't a way to patch program to remove
>  > > bugs or to introduce debugging tests; they are a way to
>  > > write OO programs where the derived class define a function
>  > > the correct way.
>  > > Do you have any supporting references for that opinion?
>
> It seems obvious enough to me.

OK, if you don't want to explain your opinion, that's fine.

> How do you debug a class without the source ?

In my example, you may just want to effectively put a breakpoint every
time a dialog opens.

> Anyway, you have no
> garanty
> that the overiding function will be called except if you know completly
> how the class works (that is, if you have the source).

If you have the header file, and the function to display the dialog is
virtual, you know at least that your function will be called wherever
the original one would be, if it's through a pointer or reference.

> But here, if the only
> argument is about debugging, I have to say that the cost of virtual
> trivial functions is very high.

This doesn't apply to my example, though.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/06
Raw View
Mark Wilden <Mark@mwilden.com> writes:

> Valentin Bonnard wrote:
> >
> > Mark Wilden <Mark@mwilden.com> writes:
> >
> >  > Valentin Bonnard wrote
> >  > > virtual functions aren't a way to patch program to remove
> >  > > bugs or to introduce debugging tests; they are a way to
> >  > > write OO programs where the derived class define a function
> >  > > the correct way.
> >  >
> >  > Do you have any supporting references for that opinion?
> >
> > It seems obvious enough to me.
>
> OK, if you don't want to explain your opinion, that's fine.

I don't have any references to books or articles stating that. But
debugging is an environment specific problem and C++ should not
be designed to work well with a particular debugger.

Do you have any references to claim that 'virtual functions are a
way to patch programs' ? I don't think that Bjarnes had debugging
in mind when he introduced them (well, I can't speak for him).

> > How do you debug a class without the source ?
>
> In my example, you may just want to effectively put a breakpoint every
> time a dialog opens.

I can easilly do that by puting a break point in the ctor (I don't
need to have the source to do that). And Dialog::draw () perhaps
won't be called when a dialog opens, but just after (that is,
immedialty after from the user point of view, but a long time after
if you step at the asm level).

> > Anyway, you have no
> > garanty
> > that the overiding function will be called except if you know completly
> > how the class works (that is, if you have the source).
>
> If you have the header file, and the function to display the dialog is
> virtual, you know at least that your function will be called wherever
> the original one would be, if it's through a pointer or reference.

Your function can still be avoided with explicit qualification
Dialog::draw ().

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Mark Wilden <Mark@mwilden.com>
Date: 1997/10/06
Raw View
Valentin Bonnard wrote:
>
> I don't have any references to books or articles stating that. But
> debugging is an environment specific problem and C++ should not
> be designed to work well with a particular debugger.

There was not the slightest environment-specific aspect about the code I
posted. Nor did it require C++ to "work well with a particular
debugger." All code must be debugged, and in fact it's a primary
advantage of OOP in general that it makes debugging easier.

> Do you have any references to claim that 'virtual functions are a
> way to patch programs'?

No. Nor do I have any reference to claim that C++ can be used to write a
World War I flight simulator.

> I don't think that Bjarnes had debugging
> in mind when he introduced them (well, I can't speak for him).

I very much doubt that Stroustrup had in mind the entire spectrum of
uses for the C++ language. He simply implemented a way to extend the
functionality of a class by deriving a new class from it and overriding
certain functions. That's what my example did.

> > In my example, you may just want to effectively put a breakpoint every
> > time a dialog opens.
>
> I can easilly do that by puting a break point in the ctor (I don't
> need to have the source to do that).

I wanted to break when the dialog is displayed, not when it was
constructed.

> Your function can still be avoided with explicit qualification
> Dialog::draw ().

If the writer of that library made such calls, I wouldn't be debugging
it, I'd be looking for a replacement. :)
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1997/10/07
Raw View
Mark Wilden wrote:
>
> Valentin Bonnard wrote:
...
> > Your function can still be avoided with explicit qualification
> > Dialog::draw ().
>
> If the writer of that library made such calls, I wouldn't be debugging
> it, I'd be looking for a replacement. :)

Are you suggesting that it is always a mistake to explicitly call the
base class version of a virtual function, or is this a judgement that is
specific to this particular application?
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/07
Raw View
Mark Wilden <Mark@mWilden.com> writes:

> Valentin Bonnard wrote:
> >
> > virtual functions aren't a way to patch program to remove
> > bugs or to introduce debugging tests; they are a way to
> > write OO programs where the derived class define a function
> > the correct way.
>
> Do you have any supporting references for that opinion?

I have just found one:

Unofficial C++ Style Guide, by Dave Goldsmith and Jack Palevich
from develop, The Apple Technical Journal, Issue 2, April 1990.

Part 2: Using Language Features, Use virtual functions the right way:

| The wrong way to use virtual functions is via a "come-from"
| mechanism like some macintosh trap patches. Don't override a
| virtual function because "I know it's called from over here with
| these parameters."  Needdless to say, this breaks havoc with
| data abstractions that are one of the major benefits of
| object-based programming.

BTW, if you don't know the possibillity to patch a trap (a trap
is a system call) on the Macintosh, I have to tell you that it
often leads to crashes (but it's possible to get it to work after
lots of tests), and the result is almost never compatible with
the next system release.

> In any event, if
> the derived class's purpose is to debug the parent class (perhaps
> because the parent source isn't available), then my example does indeed
> define the function the correct way.

In this example, yes. But what about this case:

class MemoryHandler
{
public:
    size_t   avail_mem () const; // implicilty virtual in C+=Wilden
    // Documented behaviour: returns the size of the free memory
    // Undocumented behaviour: I won't tell you

    ...
};

Then you derive:

size_t   MyMHandler::avail_mem () const
{
    cerr << "avail_mem called\n";
    return MemoryHandler::avail_mem ();
}

The use of cerr may change the available memory, but
you call the base class version after, so it seems
correct... until I tell you the undocmented behaviour,
which is: can be called at interrupt time, and output
to cerr certainly can't be done at interrupt time.

Note that this undocumented behaviour is only used
by other MemoryHandler members and shouldn't be used
by clients of MemoryHandler; it can appear or
disappear from a release of this class to the next.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Mark Wilden <Mark@mwilden.com>
Date: 1997/10/07
Raw View
James Kuyper wrote:
>
> Are you suggesting that it is always a mistake to explicitly call the
> base class version of a virtual function, or is this a judgement that is
> specific to this particular application?

No, I was suggesting it would be a mistake for the base class code
itself to call its own virtual function nonvirtually.

Of course, it's fine to explicitly call the base class method from a
derived class method, but that would still allow my client code to
override the derived class method and get my debugging code called.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1997/10/08
Raw View
Valentin Bonnard wrote:
>
> Mark Wilden <Mark@mWilden.com> writes:
>
> > Valentin Bonnard wrote:
> > >
> > > Let's say you have the following GUI classes:
> > >
> > > class Window {
> > >     virtual void draw () = 0;
> > > };
> > >
> > > class Dialog {
> > >     void draw ()
> > >     {
> > >         for_each (items.begin (), items.end (),
> > >                   ptr_mem_fun (DialogItem::draw));
> > >     }
> > >     list<DialogItem> items;
> > > };
>
> [...]
>
> > > You might want to declare Dialog::draw () final as at this point,
> > > behaviour should be changed by deriving from DialogItem, not Dialog.
> >
> > That would prevent you from doing something like this:
> >
> >  struct DebugDialog : Dialog {
> >     void draw()
> >     {
> >         cout << "About to draw dialog" << endl;
> >         Dialog::draw();
> >         cout << "Done drawing dialog" << endl;
> >     }
> >  };
>
> But any non-virtual function prevents you from doing that.
>
> virtual functions aren't a way to patch program to remove
> bugs or to introduce debugging tests; they are a way to
> write OO programs where the derived class define a function
> the correct way.
>

But there are other possibilities to extend this:

class HideableDialog: public Dialog
{
  bool Hidden;
public:
  void draw()
  {
    if(Hidden)
      return;  // we don't draw a hidden dialog!
    Dialog::draw();
  }
};

class ComplexDialog: public Dialog
{
public:
  void draw()
  {
    Screen.Lock(); // prevent changes to be written immediatly
    Dialog::draw();
    Screen.Unlock(); // Now the complete dialog appears at once
  }
};

class TopDialog: public Dialog
{
public:
  void draw()
  {
    RaiseWindow();
          // Make sure this Dialog is not hidden by another window
    Dialog::draw()
  }
};

It seems that we really need a force_call mechanism (see my earlier
posting in this thread)...

[...]
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/08
Raw View
Christopher Eltschka wrote:
>
> Valentin Bonnard wrote:
> >
> > Mark Wilden <Mark@mWilden.com> writes:
> >
> > > Valentin Bonnard wrote:
> > > >
> > > > Let's say you have the following GUI classes:
> > > >
> > > > class Window {
> > > >     virtual void draw () = 0;
> > > > };
> > > >
> > > > class Dialog {
> > > >     void draw ()
> > > >     {
> > > >         for_each (items.begin (), items.end (),
> > > >                   ptr_mem_fun (DialogItem::draw));
> > > >     }
> > > >     list<DialogItem> items;
> > > > };
> >
> > [...]
> >
> > > > You might want to declare Dialog::draw () final as at this point,
> > > > behaviour should be changed by deriving from DialogItem, not Dialog.
> > >
> > > That would prevent you from doing something like this:

[...]

> But there are other possibilities to extend this:
>
> class HideableDialog: public Dialog
> {
>   bool Hidden;
> public:
>   void draw()
>   {
>     if(Hidden)
>       return;  // we don't draw a hidden dialog!
>     Dialog::draw();
>   }
> };

Interresting. Other posters wanted additionnal behaviour,
and pretended that the Liskov Substitution Principle was
respected because the base class version is called, but
you don't even do that.

Please note that the window itself will be drawn, and that
the user will have to clic in invisible button on order to
close the dialog box.

Also, if the user clic on an item of type derived from
button, button::draw will be called directly.

> class ComplexDialog: public Dialog
> {
> public:
>   void draw()
>   {
>     Screen.Lock(); // prevent changes to be written immediatly
>     Dialog::draw();
>     Screen.Unlock(); // Now the complete dialog appears at once
>   }
> };

Will it work even if Dialog::draw() does the locking ? Anyway,
ComplexDialog::draw() isn't garantied to be called when drawing
the dialog.

I don't want you to do that. A set of virtual functions define
the range of modifiable behaviour (or behaviour you must define
if the function is pure virtual). The base class won't assume
anything about it except that it will be in the range of allowed
behaviours. Trying to cheat with that, and changing the behaviour
of other functions is a bad idea, just like casting to remove const
or trying to read private data (with a cast).

Writing virtual is a contract with the derived classes; it means:
define that as you want, but for this non-virtual function, I (the
base class) know the right way to do it, so don't change it.

With the same reasonning, do you want to overide all the private
undocumented functions ? Sounds like a good way to become dependant
on changing properties, and to break the open-close principle and
OO programming.

So IMO in a good OO language, functions shouldn't be virtual by
default, an final should exist (with some syntax, writing 'final'
or not).

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1997/10/10
Raw View
Christopher Eltschka wrote:
>
> James Kuyper wrote:
> >
> > John Potter wrote:
...
> > > See the C++ faq for why a circle is-not-an-elipse which is the same
> > > reason that a square is-not-a-rectangle.  Final is only an excuse for
> > > an ill designed hierarchy in these cases.
> >
> > The C++ faq is a big place. Could you be more specific? I couldn't find
> > anything that I recognised as being relevant.
>
> Well, it's just easy to find:

I made a bizarre assumption; since the original message was posted to
comp.std.c++, and not cross-posted to any other group, I assumed that
the "C++ faq" it was referring to is the one linked to at the bottom of
every message posted to that newsgroup. I can't imagine how I could have
made such a mistake :-) Someone finally sent me e-mail explaining the it
was the comp.lang.c++ faq that had this information. I wish the orginal
poster had provided a fully qualified web link, like this: <
http://www.cerfnet.com/~mpcline/c++-faq-lite/proper-inheritance.html#[21.6]>
Many e-mail readers will allow you to click on such a link to bring up
the corresponding web page.

I've never contested the claim that a Circle is not a kind of an
Ellipse; I just wanted to know what the argument was. Having read the
argument, I am reluctantly forced to agree.
I found the fundamental argument that convinced me by looking for
previous discussions of the topic using DejaNews. Consider the multiple
inheritence required for Point by the opposite point of view: the same
argument that says that a Circle is an Ellipse with ellipticity==1.0,
also says that a Point is a Circle with radius==0.0. However, a Point is
also a Square with side==0.0. By that argument, a Point should, in fact,
be multiply inherited from any Shape with an adjustable size, in the
limit that the size goes to 0. This is patently riduculous.

I think the correct relationship is that there might be a need for a
function which converts a 'const Circle&' to a 'const Ellipse&'; this
would allow me to pass a Circle to any function that reads an Ellipse
object, but doesn't change it.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: anatoli@zippo.com
Date: 1997/09/28
Raw View
In article <01bccaf7$1d8f6180$3282440c@worldnet.worldnet.att.net>, "Cristian
says...
>
>anatoli <anatoli.spam.please.net@zippo.com> wrote in article
>>
>> Why, oh why people keep demanding the "final" keyword, instead of
>> demanding the "invariant" keyword?
>>
>
>Because there is already a "final" in Java. It may not be a good choice
>though...

Sorry, unclear wording on my part.  I mean features (language mechanisms),
not just keywords.

Freezing (finalizing) an implementation is a poor technique to
ensure invariants.  If you wish to maintain a class invariant, you probably
need a language mechanism designed to do just that -- maintaining
class invariants.  Some languages, most notably Eiffel and Sather, have such
mechanisms; C++ and Java don't (or at least it's difficult to implement in
them).

regards
--
anatoli (at) ptc (dot) com
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Bradd W. Szonye" <bradds@concentric.net>
Date: 1997/09/29
Raw View
John Potter <jpotter@falcon.lhup.edu> wrote in article
<609n9p$fvk$1@pigpen.csrlink.net>...
>
> See the C++ faq for why a circle is-not-an-elipse which is the same
> reason that a square is-not-a-rectangle.  Final is only an excuse for
> an ill designed hierarchy in these cases.

But claiming that a circle is-an ellipse is not necessarily a sign of an
ill-designed hierarchy, and I don't think that it's a good counter-argument
against 'final'. (I don't know whether 'final' is a good idea, I'm just
refuting this counter-argument.)

Deriving circles from ellipses and squares from rectangles is not in itself
a poor design. Making ellipses/rectangles "mutable"--that is, allowing a
user to change the dimensions for a given object after they're set in the
constructor--does not lend itself well to circle/square inheritance. But
there's still a valid square-is-a-rectangle hierarchy, so long as you're
careful about which methods a rectangle provides: don't allow things that
squares can't do.

Actually I think that 'aspect_ratio' is a good example of the kind of
method that should be final, because below a certain point in the
hierarchy, it becomes an invariant. Similar examples would be
'rational_number::denominator / integer::denominator' and 'integer::sign /
natural_number::sign'. There may be good reasons for not setting up
square->rectangle, natural->integer, and integer->rational, but if those
subclasses make sense for your hierarchy, then so does 'final'.

The 'integer::denominator' method is probably a better example than
'square::aspect_ratio', since a denominator is an inherent property of a
rational number, while an aspect ratio is a derived property. Handling the
aspect ratio is more likely a job for overloaded or specialized functions
out-of-class; working with rational numbers (which are potentially
integers) almost certainly requires being able to get the number's
denominator, and so the property should be in-class--and 'final' for
integers.

(This of course assumes that rational_numbers, once created, don't let you
change the value, but only provide methods for deriving new values from
existing ones. There's still the problem of how you deal with
some_integer_variable = some_rational. It's the usual problem with making
base classes concrete. The fact that it's a problem at all may say
something about pure functional vs. imperative languages.)
--
Bradd W. Szonye
bradds@concentric.net
http://www.concentric.net/~Bradds
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1997/09/24
Raw View
"Cristian Georgescu" <Cristian.Georgescu@worldnet.att.net> wrote:

: Colin Rafferty <craffert@ml.com> wrote in article
: <ocru3fh8j52.fsf@ml.com>...
: > If you have an example of where `final' is needed in your object model
: > (percieved efficiency doesn't count), please give it.


: class Square : public Rectangle {
: class Circle : public Elipse {

See the C++ faq for why a circle is-not-an-elipse which is the same
reason that a square is-not-a-rectangle.  Final is only an excuse for
an ill designed hierarchy in these cases.

John
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Cristian Georgescu" <Cristian.Georgescu@worldnet.att.net>
Date: 1997/09/24
Raw View
Colin Rafferty <craffert@ml.com> wrote in article
<ocru3fh8j52.fsf@ml.com>...
> If you have an example of where `final' is needed in your object model
> (percieved efficiency doesn't count), please give it.

I think that the folollowing might be a good example of a function that
has to be virtual in the base class "Rectangle" and would be great to be
final in one of the derived class "Square":

class Shape {
 virtual double AspectRatio() const = 0;
};

class Rectangle : public Shape {
 const double length_;
 const double width_;
public:
 double Length() const {return length_;}
 double Width()  const {return width_;}

 Rectangle(double length, double width): length_(length), width_(width){};

 virtual double AspectRatio() const {return length_/width_;}
};

class Square : public Rectangle {
public:

 Square(double size): Rectangle(size, size){};

 virtual double AspectRatio() const {return 1.0;}
};

(IMO) The Square::AspectRatio() should be definitely a candidate to be
final.

Remark 1. Square::AspectRatio() is an invariant of the Square with respect
to
the Rectangle::AspectRatio() which is not.

Remark 2. There is no need (and no good) of redefining
Square::AspectRatio() in a class derived from Square.

Remark 3. There is a good reson in defining the AspectRatio() as a virual
function. For instance you could imagine to define an aspect ratio for
other shapes, like the elipse:

class Elipse : public Shape {
 const double length_;
 const double width_;
public:
 double Length() const {return length_;}
 double Width()  const {return width_;}

 Elipse(double length, double width): length_(length), width_(width){};

 virtual double AspectRatio() const {return length_/width_;}
};

class Circle : public Elipse {
public:

 Circle(double size): Elipse(size, size){};

 virtual double AspectRatio() const {return 1.0;}
};

Remark 4. One may finally argue that there is no need for overriding the
Square::AspectRatio() other than the reason of efficiency. It is true in
this example: the Rectangle::AspectRatio() {return length_/width_;} does a
perfect job for the Square also. But other examples may involve a more
complicated computation (not just a simple division).

--
Cristian Georgescu
_________________________________________________
    Smith Industries
    Aerospace & Defense Systems
    7-9 Vreeland Road,
    Florham Park, NJ 07932, USA.
_________________________________________________
E-mail: Georgescu_Christian@si.com
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1997/09/25
Raw View
John Potter wrote:
>
> "Cristian Georgescu" <Cristian.Georgescu@worldnet.att.net> wrote:
>
> : Colin Rafferty <craffert@ml.com> wrote in article
> : <ocru3fh8j52.fsf@ml.com>...
> : > If you have an example of where `final' is needed in your object model
> : > (percieved efficiency doesn't count), please give it.
>
> : class Square : public Rectangle {
> : class Circle : public Elipse {
>
> See the C++ faq for why a circle is-not-an-elipse which is the same
> reason that a square is-not-a-rectangle.  Final is only an excuse for
> an ill designed hierarchy in these cases.

The C++ faq is a big place. Could you be more specific? I couldn't find
anything that I recognised as being relevant.
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: anatoli <anatoli.spam.please.net@zippo.com>
Date: 1997/09/25
Raw View
In article <60a10k$ns@bgtnsc03.worldnet.att.net>, Cristian says...

[example with Shape, Square and AspectRatio snipped]

>(IMO) The Square::AspectRatio() should be definitely a candidate to be
>final.
>
>Remark 1. Square::AspectRatio() is an invariant of the Square with respect
>to
>the Rectangle::AspectRatio() which is not.

Just one question.

Why, oh why people keep demanding the "final" keyword, instead of
demanding the "invariant" keyword?

--
anatoli (at) ptc (dot) com
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: "Bill Wade" <bill.wade@stoner.com>
Date: 1997/09/26
Raw View
John Potter <jpotter@falcon.lhup.edu> wrote in article
<609n9p$fvk$1@pigpen.csrlink.net>...
> "Cristian Georgescu" <Cristian.Georgescu@worldnet.att.net> wrote:
>
> : Colin Rafferty <craffert@ml.com> wrote in article
> : <ocru3fh8j52.fsf@ml.com>...
> : > If you have an example of where `final' is needed in your object
model
> : > (percieved efficiency doesn't count), please give it.
>
>
> : class Square : public Rectangle {
> : class Circle : public Elipse {
>
> See the C++ faq for why a circle is-not-an-elipse which is the same
> reason that a square is-not-a-rectangle.  Final is only an excuse for
> an ill designed hierarchy in these cases.

The example in the faq applies only for non-const squares and rectangles.
In Cristian's example Rectangle length and width are const, so the faq
example does not apply.  Obviously if
  void Shape::Distort(const ArcadeMirror&); // Morph this shape
exists then the Faq example correctly implies that rectangles are not
shapes.  However there are many IMO good examples of class hierarchies
where rectangles are shapes.  The only requirement is that "Shape" not make
any promises that a rectangle can't keep.  Likewise it is ok for a square
to be a rectangle in hierarchies where rectangle doesn't make any promises
that a square can't keep.

You might argue that Shape::Distort should return a new shape and leave the
original shape untouched.  That may be a reasonable design decision.  If
so, to have Rectangle::SetWidth return a new rectangle and leave the
original untouched may also be a reasonable design decision.

Certainly there are situations where 'final' could allow improved
optimization.  There are plenty of other areas where new keywords could
improve optimization (noalias variants, really_const for reference and
pointer arguments, a keyword for relaxed restrictions on
common-sub-expression optimizations).

'Final' can also improve type safety (it can prevent programmers from
writing a class, derived from Rectangle, where Area() returns a different
value than Length() * Width()).  Again, there are  other potential keywords
which can improve type safety (such as really_const which would prevent
const_cast, or 'override' which says I think some base class has already
declared this function virtual).

At this point I feel that 'final' hasn't demonstrated enough benefits for
inclusion in the standard.  There are plenty of good reasons to be
conservative in making changes to the standard.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Cristian Georgescu" <Cristian.Georgescu@worldnet.att.net>
Date: 1997/09/26
Raw View
John Potter <jpotter@falcon.lhup.edu> wrote in article
> See the C++ faq for why a circle is-not-an-elipse which is the same
> reason that a square is-not-a-rectangle.  Final is only an excuse for
> an ill designed hierarchy in these cases.
>

Let me explain this:

If you suppose that an elipse is resizable, and obviously a circle is not
resizable, then a circle Is NOT an elipse. This is the example in the FAQ
you refer to. However (and if one reads with atention the article in the
FAQ) the resizability of the elipse is essential to the discussion why a
circle cannot be derived from an elipse.

In the case an elipse is not resizable (the length and the width of the
elipse are fixed) then a circle can be an elipse. This is the case if the
"length" and "width" are constants attributes of the elipse, and they are
initialized in the constructor.

The example with the Rectangle and the Square is analog to the example with
the Elipse and the Circle. Again if the if the "length" and "width" are
constants attributes of the Rectangle, then you can derive a Square from a
Rectangle.

The example is given below. Read it attentively (and remark that "length"
and "width" ARE constants), *and* the example from the FAQ (where "length"
and "width" are NOT constants) and you will realize that in the example I
give: Square IsA Rectangle, whereas in the example from the FAQ: square
is-not-a-rectangle.

----------------------------------------------------------------------------


class Shape {
 virtual double AspectRatio() const = 0;
};

class Rectangle : public Shape {
 const double length_;
 const double width_;
public:
 double Length() const {return length_;}
 double Width()  const {return width_;}

 Rectangle(double length, double width): length_(length), width_(width){};

 virtual double AspectRatio() const {return length_/width_;}
};

class Square : public Rectangle {
public:

 Square(double size): Rectangle(size, size){};

 virtual double AspectRatio() const {return 1.0;}
};

----------------------------------------------------------------------------


(IMO) The Square::AspectRatio() should be definitely a candidate to be
final.

Remark 1. Square::AspectRatio() is an invariant of the Square with respect
to
the Rectangle::AspectRatio() which is not.

Remark 2. There is no need (and no good) of redefining
Square::AspectRatio() in a class derived from Square.

Remark 3. There is a good reson in defining the AspectRatio() as a virual
function. For instance you could imagine to define an aspect ratio for
other shapes, like the elipse:

class Elipse : public Shape {
 const double length_;
 const double width_;
public:
 double Length() const {return length_;}
 double Width()  const {return width_;}

 Elipse(double length, double width): length_(length), width_(width){};

 virtual double AspectRatio() const {return length_/width_;}
};

class Circle : public Elipse {
public:

 Circle(double size): Elipse(size, size){};

 virtual double AspectRatio() const {return 1.0;}
};


--
Cristian Georgescu
_________________________________________________
    Smith Industries
    Aerospace & Defense Systems
    7-9 Vreeland Road,
    Florham Park, NJ 07932, USA.
_________________________________________________
E-mail: Georgescu_Christian@si.com
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/09/26
Raw View
Anatoli <anatoli@spam.net> writes:

> Consider:
>
> /*abstract */ class Shape

[members deleted, but look at the inheritence]

> class Rectangle : public Shape

> class Square : public Rectangle

> class MiteredSquare : public Square

> class RoundedSquare : public Square

Given the name Square, it's wrong (at least I don't like that). It
should be SortOfSquare, SortOfRectangle.

The first posters really wanted a rectangle and a square (as
they didn't wrote the contrary). RoundedSquare ISN'T-A Square,
but IS-A SortOfSquare.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1997/09/26
Raw View
John Potter wrote:
...
> See the C++ faq for why a circle is-not-an-elipse which is the same
> reason that a square is-not-a-rectangle.  Final is only an excuse for
> an ill designed hierarchy in these cases.

Could you please post a specific URL that would take me directly to that
discussion? I've been wandering around in
<http://reality.sgi.com/employees/austern_mti/std-c++/faq.html> without
finding anything that referred to circles or ellipses.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/09/26
Raw View
Mark Wilden <Mark@mWilden.com> writes:

> Valentin Bonnard wrote:
> >
> > Let's say you have the following GUI classes:
> >
> > class Window {
> >     virtual void draw () = 0;
> > };
> >
> > class Dialog {
> >     void draw ()
> >     {
> >         for_each (items.begin (), items.end (),
> >                   ptr_mem_fun (DialogItem::draw));
> >     }
> >     list<DialogItem> items;
> > };

[...]

> > You might want to declare Dialog::draw () final as at this point,
> > behaviour should be changed by deriving from DialogItem, not Dialog.
>
> That would prevent you from doing something like this:
>
>  struct DebugDialog : Dialog {
>     void draw()
>     {
>         cout << "About to draw dialog" << endl;
>         Dialog::draw();
>         cout << "Done drawing dialog" << endl;
>     }
>  };

But any non-virtual function prevents you from doing that.

virtual functions aren't a way to patch program to remove
bugs or to introduce debugging tests; they are a way to
write OO programs where the derived class define a function
the correct way.

Your argument is against non-virtual functions (thus all
non-members functions), not against final.

Remember: the original argument was: since we have
non-virtual functions, we should have final functions
(ie non-virtual functions overiding from virtual
functions).

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: "Cristian Georgescu" <Cristian.Georgescu@worldnet.att.net>
Date: 1997/09/27
Raw View
anatoli <anatoli.spam.please.net@zippo.com> wrote in article
>
> Why, oh why people keep demanding the "final" keyword, instead of
> demanding the "invariant" keyword?
>

Because there is already a "final" in Java. It may not be a good choice
though...
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1997/09/27
Raw View
James Kuyper <kuyper@wizard.net> wrote:

: John Potter wrote:
: ...
: > See the C++ faq for why a circle is-not-an-elipse which is the same
: > reason that a square is-not-a-rectangle.  Final is only an excuse for
: > an ill designed hierarchy in these cases.

: Could you please post a specific URL that would take me directly to that
: discussion? I've been wandering around in
: <http://reality.sgi.com/employees/austern_mti/std-c++/faq.html> without
: finding anything that referred to circles or ellipses.

Yes, it is not as easy to find in the groups as it once was.  And it
is the C++ faq not the c++standard faq.  Sorry for any confusion.

http://www.cerfnet.com/~mpcline/c++-faq-lite

Items 21.6-9

John
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Mark Wilden <Mark@mWilden.com>
Date: 1997/09/18
Raw View
Valentin Bonnard wrote:
>
> Let's say you have the following GUI classes:
>
> class Window {
>     virtual void draw () = 0;
> };
>
> class Dialog {
>     void draw ()
>     {
>         for_each (items.begin (), items.end (),
>                   ptr_mem_fun (DialogItem::draw));
>     }
>     list<DialogItem> items;
> };
>
> class DialogItem {
>     virtual void draw () = 0;
> };
>
> You might want to declare Dialog::draw () final as at this point,
> behaviour should be changed by deriving from DialogItem, not Dialog.

That would prevent you from doing something like this:

 struct DebugDialog : Dialog {
    void draw()
    {
        cout << "About to draw dialog" << endl;
        Dialog::draw();
        cout << "Done drawing dialog" << endl;
    }
 };
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Colin Rafferty <craffert@ml.com>
Date: 1997/09/18
Raw View
Fred J Dukes writes:
> Colin Rafferty <craffert@ml.com> wrote in article <ocr202p89e1.fsf@ml.com>:

>> I will reassert my claim from the beginning of this thread.  There is no
>> real-life need for `final', other than due to a poorly designed base
>> class.

> From various postings in this thread I know there are ways to work around
> such problems. However, they aren't trivial. Being able to declare such a
> function 'final' would, in this case, make our jobs easier.

All the examples that I have seen in this thread (and I have seen a lot
:-) have been poor designs in the first place.  There had not been one
`final' function that should have been virtual in the first place.

> In COM/OLE programming in C++, the system defines a lot of interfaces as
> pure virtual base classes. The easiest way for me to create an class B that
> supports some collection of these interfaces is to multiply inherit from
> them.

This is the only kind of example that I know of (Java style Interface)
that might merit needing `final'.  However, it seems to me that this
idiom is something that will be dying out.

In Java, and in earlier C++ implementation (the ones lacking templated
member functions), Interface classes are necessary.  However, with the
abilities that generic programming gives you, there is now no good
reason to have Interface classes anymore.

Now, rather than a framework function taking a pointer to an Interface
class, so that it can call a abstract virtual function, it can take a
Functor object.

Frameworks that use Functors (and their friends) are much better than
ones that use Interface classes.  They allow callbacks to happen to
objects that don't even know about the framework.  They avoid possible
name collisions between multiply inherited Interfaces.  They avoid the
need for the called object to even have a vtbl.

I am not familiar with COM/OLE itself, but every framework that I know
that uses Interface classes can be better rewritten using generic
programming.

--
#!/bin/perl -sp0777i<X+d*lMLa^*lN%0]dsXx++lMlN/dsM0<j]dsj
$/=unpack('H*',$_);$_=`echo 16dio\U$k"SK$/SM$n\EsN0p[lN*1
lK[d2%Sa2/d0$^Ixp"|dc`;s/\W//g;$_=pack('H*',/((..)*)$/)
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: "Cristian Georgescu" <Cristian.Georgescu@worldnet.att.net>
Date: 1997/09/19
Raw View
Colin Rafferty <craffert@ml.com> wrote in article
<ocrafhaa5v0.fsf@ml.com>...
> All the examples that I have seen in this thread (and I have seen a lot
> :-) have been poor designs in the first place.  There had not been one
> `final' function that should have been virtual in the first place.

You may use a library that "has been poorly designed in the first place"
but you may have no other choice. "Final" may be useful in such a
situation, at least.

If you may prove that *any* usage of "final" is "poor design" then I would
be interested.

Then, there are features in C++ that allow "poor design" like the
possibility to declare protected data members.

--
Cristian Georgescu
_________________________________________________
    Smith Industries
    Aerospace & Defense Systems
    7-9 Vreeland Road,
    Florham Park, NJ 07932, USA.
_________________________________________________
E-mail: Georgescu_Christian@si.com
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Colin Rafferty <craffert@ml.com>
Date: 1997/09/20
Raw View
James Kuyper writes:

> For those who are opposed to the idea of 'final':

I am opposed to the idea of `final' because I am opposed to poor design.

> Do you admit to the existence of any reason for ever defining a
> non-virtual member function (other than the trivial one of avoiding
> virtual overhead costs)?

> What guarantees that this reason will never justify declaring a virtual
> function override to be 'final'?

Experience.  I have yet to see an example of a need for `final' in a
well-designed object model.

In this forum, I have asked for examples of a need for this, and have
not yet seen one.  The only real example of the need for this is in
implementing Java-style `Interface' classes.  However, the only reason
that this style of programming exists is because of the lack of
templated member functions in all but the lastest C++ compilers.

Will templated member functions, the need for `Interface' classes goes
away, as does the only possible reason for `final'.

If you have an example of where `final' is needed in your object model
(percieved efficiency doesn't count), please give it.

--
-export-a-crypto-system-sig -RSA-3-lines-PERL
#!/bin/perl -sp0777i<X+d*lMLa^*lN%0]dsXx++lMlN/dsM0<j]dsj
$/=unpack('H*',$_);$_=`echo 16dio\U$k"SK$/SM$n\EsN0p[lN*1
lK[d2%Sa2/d0$^Ixp"|dc`;s/\W//g;$_=pack('H*',/((..)*)$/)
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: ark@research.att.com (Andrew Koenig)
Date: 1997/09/20
Raw View
In article <34213D4E.41C6@wizard.net> James Kuyper <kuyper@wizard.net> writes:

> For those who are opposed to the idea of 'final':

> Do you admit to the existence of any reason for ever defining a
> non-virtual member function (other than the trivial one of avoiding
> virtual overhead costs)?

Sure -- see Chapter 11 of `Ruminations on C++.'

> What guarantees that this reason will never justify declaring a virtual
> function override to be 'final'?

I don't understand why this question is relevant.

Among other things, the chapter gives an example of overriding
a non-virtual function in a derived class.
--
    --Andrew Koenig
      ark@research.att.com
      http://www.research.att.com/info/ark
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Cristian Georgescu" <Cristian.Georgescu@worldnet.att.net>
Date: 1997/09/21
Raw View
Andrew Koenig <ark@research.att.com> wrote in article
<EGrqMH.LwJ@research.att.com>...
> Among other things, the chapter gives an example of overriding
> a non-virtual function in a derived class.

I thought that you can override *only* virtual functions. Non-virtual
functions are either hidden (by redefinition with same signature in derived
class) or overloaded (different signature). Am I right?


--
Cristian Georgescu
_________________________________________________
    Smith Industries
    Aerospace & Defense Systems
    7-9 Vreeland Road,
    Florham Park, NJ 07932, USA.
_________________________________________________
E-mail: Georgescu_Christian@si.com
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Mark Wilden <Mark@mwilden.com>
Date: 1997/09/21
Raw View
Cristian Georgescu wrote:
>
> I thought that you can override *only* virtual functions. Non-virtual
> functions are either hidden (by redefinition with same signature in derived
> class) or overloaded (different signature). Am I right?

You may be aware of this, but just to be clear, a function with the same
name but a different signature in a derived class hides the function
with the same name in the base class, and does not overload it. You can
only overload functions in the same scope.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1997/09/23
Raw View
Colin Rafferty wrote:
>
> James Kuyper writes:
>
> > For those who are opposed to the idea of 'final':
>
> I am opposed to the idea of `final' because I am opposed to poor design.

You're begging the question. I want to understand why you think that
'final' is inherently poor design.

>
> > Do you admit to the existence of any reason for ever defining a
> > non-virtual member function (other than the trivial one of avoiding
> > virtual overhead costs)?
>
> > What guarantees that this reason will never justify declaring a virtual
> > function override to be 'final'?
>
> Experience.  I have yet to see an example of a need for `final' in a
> well-designed object model.

I can't download your experience from usenet. I'm looking for words that
explain your experience. The fact that you haven't seen an example
doesn't mean that one doesn't exist. On the other hand, a well
constructed argument could apply even to cases you haven't seen.

...
> If you have an example of where `final' is needed in your object model
> (percieved efficiency doesn't count), please give it.

Does actual (rather than percieved) efficiency count? In real life
efficiency often matters.
However, I don't see a significant efficiency issue here. This is
primarily a design issue. A base class function not declared virtual is
guaranteed to be the version called, if it is called from the base
class. It is currently not possible to obtain such a guarantee for a
function which overrides a virtual function, because a further-derived
class can always override it yet again. The issue is whether that
guarantee is ever needed in that case.

I have tried to produce such an example, so have several other people.
I've read your counter arguments, and don't understand them well enough
to try to refute them. I've concluded that what I need is a clear,
general statement from you as to what you consider to be proper reasons
for deciding whether to make a function virtual. Can you provide one?
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Cristian Georgescu" <Cristian.Georgescu@worldnet.att.net>
Date: 1997/09/23
Raw View
Colin Rafferty <craffert@ml.com> wrote in article
<ocru3fh8j52.fsf@ml.com>...
> If you have an example of where `final' is needed in your object model
> (percieved efficiency doesn't count), please give it.

class Shape {
 virtual double AspectRatio() const = 0;
};

class Rectangle : public Shape {
 const double length_;
 const double width_;
public:
 double Length() const {return length_;}
 double Width()  const {return width_;}

 Rectangle(double length, double width): length_(length), width_(width){};

 virtual double AspectRatio() const {return length_/width_;}
};

class Square : public Rectangle {
public:

 Square(double size): Rectangle(size, size){};

 virtual double AspectRatio() const {return 1.0;}
};

The Square::AspectRatio() should be definitely a candidate to be final.

Remark 1. Square::AspectRatio() is an invariant of the Square with respect
to
the Rectangle::AspectRatio() which is not.

Remark 2. There is no need (and no good) of redefining
Square::AspectRatio() in a class derived from Square.

Remark 3. There is a good reson in defining the AspectRatio() as a virual
function. For instance you could imagine to define an aspect ratio for
other shapes, like the elipse:

class Elipse : public Shape {
 const double length_;
 const double width_;
public:
 double Length() const {return length_;}
 double Width()  const {return width_;}

 Elipse(double length, double width): length_(length), width_(width){};

 virtual double AspectRatio() const {return length_/width_;}
};

class Circle : public Elipse {
public:

 Circle(double size): Elipse(size, size){};

 virtual double AspectRatio() const {return 1.0;}
};

Remark 4. One may finally argue that there is no need for overriding the
Square::AspectRatio() other than the reason of efficiency. It is true in
this example: the Rectangle::AspectRatio() {return length_/width_;} does a
perfect job for the Square also. But other examples may involve a more
complicated computation (not just a simple division).

--
Cristian Georgescu
_________________________________________________
    Smith Industries
    Aerospace & Defense Systems
    7-9 Vreeland Road,
    Florham Park, NJ 07932, USA.
_________________________________________________
E-mail: Georgescu_Christian@si.com
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: "Cristian Georgescu" <Cristian.Georgescu@worldnet.att.net>
Date: 1997/09/14
Raw View
James Kuyper <kuyper@wizard.net> wrote in article
<341957A6.41C6@wizard.net>...
> ... Ideally, I would like to have many
> different mathematical vector classes, with many different element types
> and storage methods, which can be added, subtracted, or multiplied
> freely with each other.

If I understand well your application is intended for heavy numerical
computation.

It may be better to have a wrapper class for Vector, and based on the
special vector you have, let the wrapper claass decide how to store the
data.

Besides, you may be better placed if you have a class Matrix !

> The expression (vec1+vec2), where 'vec1' and
> 'vec2' are both mathematical vectors, should return a vector using the
> same storage method as vec1, and an element type that is the same as
> that returned by vec1[0]+vec2[0].

The better thing is probably to raise an exception.
Then add a method Vector::Padd(int n) to extend a vector to dimension n by
padding with zeros.

You may want to try to look how this problems are solved in specialized
applications in the field: I have used a lot Matlab (which is an
interpretor based on Matrix type) an there the addition of 2 vectors of
different sizes goes as following:

;
; x= [1 2 3]

x =

     1     2     3

; y = [1 2 3 4 5 6]

y =

     1     2     3     4     5     6

; z= x + y
??? Error using ==> +
Matrix dimensions must agree.

;


Padding is done like this:

; a = [ x, 10]

a =

     1     2     3    10

;

You also have a reshape function:


; help reshape

 RESHAPE Change size.
  RESHAPE(X,M,N) returns the M-by-N matrix whose elements
  are taken columnwise from X.  An error results if X does
  not have M*N elements.

;

Hope it helps.

--
Cristian Georgescu
_________________________________________________
    Smith Industries
    Aerospace & Defense Systems
    7-9 Vreeland Road,
    Florham Park, NJ 07932, USA.
_________________________________________________
E-mail: Georgescu_Christian@si.com
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Colin Rafferty <craffert@ml.com>
Date: 1997/09/15
Raw View
James Kuyper writes:
 > Colin Rafferty wrote:
 >> James Kuyper writes:
 >> > Colin Rafferty wrote:
 >> >> In article <5v1i5j$qrg$1@mail.pl.unisys.com>, Brett writes:
 >>
 >> >> > Personally, I think that a function should almost never be defined final
 >> >> > because it cancels out much of the usefulness of object-oriented code design.
 >> >> > I want to be able to extend and modify my classes as much as possible.
 >>
 >> >> That is exactly my point.  It is fascistic for a subclass designer to
 >> >> override the design of the base class designer.
 >>
 >> > I don't have much C++ experience, so what I'm about to describe may be
 >> > poorly designed. I designed it shortly after I first learned about C++,
 >> > and long before I ever heard about the STL, so it may duplicate some
 >> > functionality in the STL (I still haven't finished reading that part of
 >> > the standard):
 >>
 >> > I had a Vector class, which defined non-virtual mathematical operator
 >> > overloads appropriate to mathematical vectors, but left the storage
 >> > method up to derived classes. Thus, length() and operator[]() were
 >> > virtual members, which were called by the mathematical operator
 >> > overloads.
 >>
 >> I would say that the design could be improved.  The storage method is an
 >> attribute of the Vector, not the behavior.  As someone else pointed out,
 >> only behavior should be virtual; attributes should is passed to the
 >> constructor, or  specialized in a template.
 >>
 >> The class `std::vector' is a perfect example of this.  Rather than only
 >> being templated on the type of the contained object, it is also
 >> templated on the allocator.
 >>
 >> Doing it this way gives the ability to use the same allocation scheme in
 >> multiple collections (not just your Vector), and avoids a "combinatorial
 >> explosion of subclasses"[1].

 > I'm still learning about templates. Ideally, I would like to have many
 > different mathematical vector classes, with many different element types
 > and storage methods, which can be added, subtracted, or multiplied
 > freely with each other. The expression (vec1+vec2), where 'vec1' and
 > 'vec2' are both mathematical vectors, should return a vector using the
 > same storage method as vec1, and an element type that is the same as
 > that returned by vec1[0]+vec2[0]. The code that does the vector
 > additions should be part of MathVector, and kept distinct from the code
 > that implements the different storage methods. How closely can this
 > ideal be achieved?

I would say that your MathVector class should be templated on the type
of element and allocation method.  You would then use a "traits" class
(MatchVectorTraits) to define conversions.  In this way, you could have
the following templated operators:

   template <class T1, class T2, class A1, class A2>
   MathVector<MathVectorTraits<T1, T2>::sum_t, A1>
   operator+(const MathVector<T1, A1>&, const MathVector<T2, A2>&);

   template <class T1, class T2, class A1, class A2>
   MathVector<MathVectorTraits<T1, T2>::product_t, A1>
   operator*(const MathVector<T1, A1>&, const MathVector<T2, A2>&);

I would suggest that you buy the Third Edition of Stroustrup's book, and
read about templates and generic programming.  He gives some lucid
examples of how things work, and how you may want to deal with this.

 > I'm undecided about the correct way to handle length mis-matches. One
 > alternative is to treat the shorter vector as if it had 0's appended.
 > Another alternative is to raise an exception. A third possibility is to
 > return a static empty ErrorVector object. The first method is the
 > simplest, but provides no way to detect the error.

It depends on the semantics of your class.  If it is an error, throw an
exception.  If it is not an error, pad the shorter with default values.
Returning an ErrorVector is definitely a suboptimal solution, given
exceptions.

 >> > The ThreeVector class implemented length() as returning a constant 3. It
 >> > used a fixed double[3] array member to store the data. Thus, it was
 >> > quicker, smaller, but less flexible than an NVector.
 >>
 >> > I cannot think any situation where it would be a good idea for a class
 >> > derived from ThreeVector to override length(). If there were a 'final'
 >> > keyword in C++, I would have used it there.
 >>
 >> This is a little goofy, but it would work:
 >>
 >> template <class TT>
 >> class FiveVector : public ThreeVector<TT> {
 >> TT rest_[2];
 >> public:
 >> virtual size_t length() const { return ThreeVector<TT>::length() + 2; }
 >> virtual TT& ref(size_t elt) {
 >> return ((elt < 2) ? rest_[elt] : ThreeVector<TT>::ref(elt - 2));
 >> }
 >> };

 > Yes, that is very goofy. It illustrates my point. Why derive FiveVector
 > from ThreeVector, rather than deriving it directly from Vector?

Because I can?  I really only included this (and the LoggingVector) for
completeness.  Realistically, I would say that none of the functions
should be virtual, and you should be using an allocator class in the
template.

--
#!/bin/perl -sp0777i<X+d*lMLa^*lN%0]dsXx++lMlN/dsM0<j]dsj
$/=unpack('H*',$_);$_=`echo 16dio\U$k"SK$/SM$n\EsN0p[lN*1
lK[d2%Sa2/d0$^Ixp"|dc`;s/\W//g;$_=pack('H*',/((..)*)$/)
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Cristian Georgescu" <Cristian.Georgescu@worldnet.att.net>
Date: 1997/09/15
Raw View
Colin Rafferty <craffert@ml.com> wrote in article
<ocrvi06d0qv.fsf@ml.com>...
> Cristian Georgescu writes:
> >> > Consider an Apple base class with a getColor() virtual
> >> > function. Then I have a YellowApple class derived from Apple, and
> >> > the getColor() overridden to return the color Yellow.
> >>
> >> > The idea is that I do not want the classes that inherit from
> >> > YellowApple to override the getColor().
>
> > I think that there is a good reason for getColor() to be virtual in the
> > base class.
>
> Colin Rafferty <craffert@ml.com> wrote:
>
> Since color is just an attribute, you don't need a virtual function.
> All you need is a constructor with the color as an argument.

I agree with you that:
----------------------

The above example may be not quite suitable however for the discussion
because
the underlying attribute can be set as a constant in the constructor, and
there is no reason why getColor should be virtual.

But ...
-------

But what happens if you have an invariant of the class, or an Attribute
that is computed not mapped to a variable in the class.

class Rectangle {
 double length_;
 double width_;
public:
 Length(){return length_;}
 Width(){return width_;}

 Rectangle(double length, double width): length_(length), width_(width){};

 virual double Area(){return length_*width_;}
 virual double AspectRatio(){return length_/width_;}
}

class Square : public Rectangle {
public:

 Square(double size): Rectangle(size, size){};

 virtual double Area(){return sqr(size);}
 virtual double AspectRatio(){return 1.0;}
}

In this case we have:

1. Square::Area() that can be seen as an algorithmic improvement of the
Rectangle::Area() in order to take into account the specificity of the
Square

This Square::Area() may be a candidate to be final.

2. Square::AspectRatio() that is an invariant of the Square with respect to
the Rectangle::AspectRatio() which is not.

This Square::AspectRatio() should be definitely a candidate to be final.

Remark:
=======
Declaring final Square::AspectRatio():

 final virtual double AspectRatio(){return 1.0;}

therefor removing the virtualness of the AspectRatio() from Square on,
would make that the classes that inherit from the Square have the
AspectRatio() function binding at compile time (with respect to class
Square) -- therefore some performance improvement! I think this may be a
good thing.

Besides, if all the functions from Square are finalized, then the classes
derived from Square would not even need a vptr table.

--
Cristian Georgescu
_________________________________________________
    Smith Industries
    Aerospace & Defense Systems
    7-9 Vreeland Road,
    Florham Park, NJ 07932, USA.
_________________________________________________
E-mail: Georgescu_Christian@si.com
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Colin Rafferty <craffert@ml.com>
Date: 1997/09/17
Raw View

Cristian Georgescu writes:
> Colin Rafferty <craffert@ml.com> wrote in article
> <ocrvi06d0qv.fsf@ml.com>...
>> Cristian Georgescu writes:
>> >> > Consider an Apple base class with a getColor() virtual
>> >> > function. Then I have a YellowApple class derived from Apple, and
>> >> > the getColor() overridden to return the color Yellow.
>> >>
>> >> > The idea is that I do not want the classes that inherit from
>> >> > YellowApple to override the getColor().
>>
>> > I think that there is a good reason for getColor() to be virtual in the
>> > base class.
>>
>> Colin Rafferty <craffert@ml.com> wrote:
>>
>> Since color is just an attribute, you don't need a virtual function.
>> All you need is a constructor with the color as an argument.

> I agree with you that:
> ----------------------

> The above example may be not quite suitable however for the discussion
> because
> the underlying attribute can be set as a constant in the constructor, and
> there is no reason why getColor should be virtual.

However, you provided the above example.  I was only following your
lead.  I requested an example of a good design that needed `final'.

> But ...
> -------

> But what happens if you have an invariant of the class, or an Attribute
> that is computed not mapped to a variable in the class.

> class Rectangle {
>  double length_;
>  double width_;
> public:
>  Length(){return length_;}
>  Width(){return width_;}

>  Rectangle(double length, double width): length_(length), width_(width){};

>  virual double Area(){return length_*width_;}
>  virual double AspectRatio(){return length_/width_;}
> }

> class Square : public Rectangle {
> public:

>  Square(double size): Rectangle(size, size){};

>  virtual double Area(){return sqr(size);}
>  virtual double AspectRatio(){return 1.0;}
> }

This is a ridiculous example, because there is no good reason for Area()
or AspectRatio() to be virtual.  None of the reasons that you give make
it worthwhile.

> In this case we have:

> 1. Square::Area() that can be seen as an algorithmic improvement of the
> Rectangle::Area() in order to take into account the specificity of the
> Square

This is wrong.  There is no good reason why sqr(x) should be faster than
(x*x).  In fact, the overhead of the virtual call makes it even worse.

> This Square::Area() may be a candidate to be final.

No, Rectangle::Area is a candidate for being non-virtual.

> 2. Square::AspectRatio() that is an invariant of the Square with respect to
> the Rectangle::AspectRatio() which is not.

But there is an invariant that Rectangle::AspectRatio() should be equal
to (length_/width_).  If you believe that a subclass of Rectangle can
override AspectRatio(), then there is no reason for Square to not have
its overridden.

> This Square::AspectRatio() should be definitely a candidate to be final.

Only because Rectangle::AspectRatio() should never have been virtual in
the first place.

Seriously, the cost of calculating (length_/width_) inline is probably
about the same as calling a virtual function.  If you are worried about
efficiency, just make Rectangle::AspectRatio() a non-virtual inline
function.

> Remark:
> =======
> Declaring final Square::AspectRatio():

>  final virtual double AspectRatio(){return 1.0;}

> therefor removing the virtualness of the AspectRatio() from Square on,
> would make that the classes that inherit from the Square have the
> AspectRatio() function binding at compile time (with respect to class
> Square) -- therefore some performance improvement! I think this may be a
> good thing.

This is only a possible improvement within the member functions of the
subclasses of Square.  External users would not have handles to anything
other than Rectangle pointers (or references).

> Besides, if all the functions from Square are finalized, then the classes
> derived from Square would not even need a vptr table.

If Square has no virtual functions, then there is no good reason to
derive from Square anyway.

I will reassert my claim from the beginning of this thread.  There is no
real-life need for `final', other than due to a poorly designed base
class.

--
#!/bin/perl -sp0777i<X+d*lMLa^*lN%0]dsXx++lMlN/dsM0<j]dsj
$/=unpack('H*',$_);$_=`echo 16dio\U$k"SK$/SM$n\EsN0p[lN*1
lK[d2%Sa2/d0$^Ixp"|dc`;s/\W//g;$_=pack('H*',/((..)*)$/)
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: spam@motu.com (David Abrahams)
Date: 1997/09/17
Raw View
On 15 Sep 1997 18:16:16 PDT, "Cristian Georgescu"
<Cristian.Georgescu@worldnet.att.net> wrote:

<snip>

>Besides, if all the functions from Square are finalized, then the classes
>derived from Square would not even need a vptr table.

Oops! Not so if the Square* can be cast to Rectangle*. Code using
Rectangle* will expect a vtbl.
(Please change 'spam' to 'abrahams' in the return address, which has been altered to foil junk mail senders.)
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/09/17
Raw View
Valentin Bonnard <bonnardv@pratique.fr> writes:

> Colin Rafferty <craffert@ml.com> writes:
>
> > Michael B Taylor writes:
> >
> > > Maybe I missing something about this whole thread, but it seems to me
> > > that the desire to declare a virtual method "final" in some derived
> > > class is the same as the desire to declare a method in a class
> > > non-virtual.

[...]

> > Steve Clamage gave a lucid example of why this is a bad idea.  I have
> > yet to see an example of why this is useful.  I cannot imagine a
> > real-life use for `final', other than due to a poorly designed base
> > class.

[...]

> Others might find additionnal examples.

Here is one.

Let's say you have the following GUI classes:

class Window {
    virtual void draw () = 0;
};

class Dialog {
    void draw ()
    {
        for_each (items.begin (), items.end (),
                  ptr_mem_fun (DialogItem::draw));
    }
    list<DialogItem> items;
};

class DialogItem {
    virtual void draw () = 0;
};

You might want to declare Dialog::draw () final as at this point,
behaviour should be changed by deriving from DialogItem, not Dialog.

In particular, any member of Dialog can assume that Dialog::draw
as the same effect as Dialog::draw (), the same undocumented
semantics...

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Anatoli <anatoli@spam.net>
Date: 1997/09/17
Raw View
In article <ocr202p89e1.fsf@ml.com>, Colin says...
>Cristian Georgescu writes:
>> This Square::Area() may be a candidate to be final.
>
>No, Rectangle::Area is a candidate for being non-virtual.

Both are wrong.

Consider:

/*abstract */ class Shape
{
  // ...
  virtual double Area () = 0;
};

class Rectangle : public Shape
{
  // ...
  virtual double Area () { return x * y; }
};

class Square : public Rectangle
{
 // ...
};

class MiteredSquare : public Square
{
  // ...
  virtual double Area () { return x * x - 2 * miter * miter; }
};

class RoundedSquare : public Square
{
  // ...
  virtual double Area () { return x * x + (PI - 4) * radius; }
  // I hope I have my geometry right!
};

Regards!

--
anatoli (at) ptc (dot) com
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: "Fred J. Dukes" <mbtaylor@microsoft.com>
Date: 1997/09/18
Raw View
Colin Rafferty <craffert@ml.com> wrote in article
<ocr202p89e1.fsf@ml.com>...
>
> I will reassert my claim from the beginning of this thread.  There is no
> real-life need for `final', other than due to a poorly designed base
> class.
>

Is there any real-life need for non-virtual functions in any class?

If so, can't you imagine a situation where it would be easier to implement
that class using a class hierarchy wherein your non-virtual function is
already virtual.



Author: "Bill Wade" <bill.wade@stoner.com>
Date: 1997/09/18
Raw View
Colin Rafferty <craffert@ml.com> wrote in article
<ocr202p89e1.fsf@ml.com>...
>
>> [ Example of square, derived from rectangle, suggestion that
square::Area()
>>   should not be overridable ]
>
> This is a ridiculous example, because there is no good reason for Area()
> or AspectRatio() to be virtual.  None of the reasons that you give make
> it worthwhile.
>   [ Other deleted ]
> Rectangle::Area is a candidate for being non-virtual.

struct Shape
{
  virtual int Area()=0;
};

struct Rectangle: public Shape
{
  const int len;
  const int wid;
  Rectangle(int l, int w);
  int Area(){ return len * wid; }
};

struct Square: public Rectange
{
  Square(int w): Rectangle(w,w){}
  int Area(){ return wid*wid; }
  ...
};

template<int width> struct FixedSquare: public Square
{
  FixedSquare(): Square(width){}
  int Area(){ return width*width; }
};

Now if you can use 'final' on an Area override you could use it in
Rectangle so that in rectangle contexts no virtual function dispatch is
required.

If you use 'final' in Square you get a slight optimization (only one read
to memory is required).

If you use 'final' in FixedSquare, Area() becomes a compile-time constant
for a reasonable compiler.

Unfortunately its not at all clear in which spot you'd want to use 'final'.
 Also, many of the advantages (from an optimization standpoint) are
available without a new keyword:

non-virtual int Rectangle::RectArea(){ return len * wid; }
       virtual int Rectangle::Area(){ return RectArea(); }

and so on for the other classes.  In a context where I know I have a
rectangle I can call RectArea and get a non-virtual inline function.  If
I'm going through a shape pointer I've got to live with what virtual
dispatch gives me.

A more compelling reason for 'final' seems to be preservation of Is-A
semantics.  It may be ok to derive from rectangle to get square (note my
rectangle has const width and length).  However if a derived class returns
an Area() which doesn't have the same value as len*wid, the derived class
is violating Is-A-Rectangle semantics and it would be nice if the compiler
would tell us.  We certainly aren't going to get compilers smart enough to
tell us, in general, of Is-A violations.  However a 'final' keyword could
prevent your rectangle from being used as a base class for a BeveledSquare
as someone else suggested.

To summerize, final
1) Makes certain optimizations easier.  In some contexts virtual function
dispatch can be converted to inline code.
2) If used judiciously could detect "accidental" overrides of base class
functions and violations of Is-A semantics
3) Adds some complexity to the language.

How long till we see the 'final' optimizations implemented for classes
using the 'no further derivation' trick?
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Colin Rafferty <craffert@ml.com>
Date: 1997/09/18
Raw View
Valentin Bonnard writes:
> Valentin Bonnard <bonnardv@pratique.fr> writes:
>> Colin Rafferty <craffert@ml.com> writes:
>> > Michael B Taylor writes:

>> > > Maybe I missing something about this whole thread, but it seems to me
>> > > that the desire to declare a virtual method "final" in some derived
>> > > class is the same as the desire to declare a method in a class
>> > > non-virtual.

>> > Steve Clamage gave a lucid example of why this is a bad idea.  I have
>> > yet to see an example of why this is useful.  I cannot imagine a
>> > real-life use for `final', other than due to a poorly designed base
>> > class.

>> Others might find additionnal examples.

> Here is one.

> Let's say you have the following GUI classes:

> class Window {
>     virtual void draw () = 0;
> };

> class Dialog {
>     void draw ()
>     {
>         for_each (items.begin (), items.end (),
>                   ptr_mem_fun (DialogItem::draw));
>     }
>     list<DialogItem> items;
> };

> class DialogItem {
>     virtual void draw () = 0;
> };

> You might want to declare Dialog::draw () final as at this point,
> behaviour should be changed by deriving from DialogItem, not Dialog.

If I want to decorate Dialog, I would have to subclass from it, and draw
myself.  Of course, I have to keep the old behavior as well.  But I want
to extend it.

class ModalDialog {
    void draw ()
    {
        // do something modal...
        Dialog::draw();
        // do something else modal...
    }
};

> In particular, any member of Dialog can assume that Dialog::draw
> as the same effect as Dialog::draw (), the same undocumented
> semantics...

Which means that any subclass of Dialog is responsible for doing the
appropriate thing.  Usually, this means calling the base class's
implementation.

--
#!/bin/perl -sp0777i<X+d*lMLa^*lN%0]dsXx++lMlN/dsM0<j]dsj
$/=unpack('H*',$_);$_=`echo 16dio\U$k"SK$/SM$n\EsN0p[lN*1
lK[d2%Sa2/d0$^Ixp"|dc`;s/\W//g;$_=pack('H*',/((..)*)$/)
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: James Kuyper <kuyper@wizard.net>
Date: 1997/09/18
Raw View
For those who are opposed to the idea of 'final':

Do you admit to the existence of any reason for ever defining a
non-virtual member function (other than the trivial one of avoiding
virtual overhead costs)?

What guarantees that this reason will never justify declaring a virtual
function override to be 'final'?
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Christian Millour <chris161@club-internet.fr>
Date: 1997/09/10
Raw View
Steve Clamage wrote:
>
> Cristian Georgescu wrote:
> >
> > The problem with 1. is that you may need a certain function to be virtual
> > through the class hierachy inside your code, but you would like that in a
> > certain leaf class (that is intended to be used by the user) the user
> > should not override the virtual function.
>
> But why?
>

I run into this problem everytime I attempt to nest `template methods'
(see `Design Patterns' p 325), as in:

class Queryable {
  ...
public:
  // template method
  void query(Whatever & into) { do_query(into); }
private:
  // hook
  virtual void do_query(Whatever & into) = 0;
};

class Cached : public Queryable {
  ...
private:
  // now the hook becomes itself a template method
  virtual void do_query(Whatever & into) {
    if (expired()) { renovate_cache(); expired(false); }
    copy_cache(into);
  }
  // hooks
  virtual void renovate_cache() = 0;
  virtual void copy_cache(Whatever & into) = 0;
};

classes derived from Cached should implement `renovate_cache'
and `copy_cache' but should not override `do_query', whose
job is done for good. Arguably, a derived class might extend
do_query (provided it was made protected rather than private)
as

void DerivedFromCached::do_query(Whatever & into) {
  // before stuff
  Cached::do_query(into);
  // after stuff
}

but any other form is likely to compromise Cached's semantics,
which is rather distressing.

So maybe the design is wrong. But what are the alternatives ?
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Colin Rafferty <craffert@ml.com>
Date: 1997/09/10
Raw View
In article <5v1i5j$qrg$1@mail.pl.unisys.com>, Brett writes:
> In article <ocr4t7zlk2o.fsf@ml.com>, Colin Rafferty <craffert@ml.com> wrote:

>> Steve Clamage gave a lucid example of why this is a bad idea.  I have
>> yet to see an example of why this is useful.  I cannot imagine a
>> real-life use for `final', other than due to a poorly designed base
>> class.

> Have you taken a look at the Java 1.02 API?  I think the number of virutal
> functions that are eventually defined final in a derived class number in the
> hundreds.

This is not the only deficiency of Java.

> Personally, I think that a function should almost never be defined final
> because it cancels out much of the usefulness of object-oriented code design.
> I want to be able to extend and modify my classes as much as possible.

That is exactly my point.  It is fascistic for a subclass designer to
override the design of the base class designer.

--
Colin
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Mark Wilden <Mark@mwilden.com>
Date: 1997/09/11
Raw View
Cristian Georgescu wrote:
>
> Suppose you have a class Apple with a virtual function getColor(); then I
> want to make a derived class GreenApple with getColor that will always
> return Green.

Since this would (probably) be a bad class design in the first place,
maybe there's a better example?

I can't think of a good use for GreenApple that couldn't better be
served simply by

 struct Apple {
    enum Color { Green, Red };
    Apple(Color, double price);
    Color getColor() const;
    double getPrice() const;
 private:
    const Color color;
    const double price;
 };

Classes should reflect behavior, not attributes--if only to avoid a
combinatorial explosion of subclasses from the union of all possible
attribute values.

I think a better example would make your point clearer.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1997/09/11
Raw View
Colin Rafferty wrote:
>
> In article <5v1i5j$qrg$1@mail.pl.unisys.com>, Brett writes:
...
> > Personally, I think that a function should almost never be defined final
> > because it cancels out much of the usefulness of object-oriented code design.
> > I want to be able to extend and modify my classes as much as possible.
>
> That is exactly my point.  It is fascistic for a subclass designer to
> override the design of the base class designer.
>

As someone else has already pointed out, any reason for making a member
function non-virtual, is a reason a derived class might want to make a
member function 'final' in the Java sense. A class is declared virtual
when its implementation in the current class is incomplete. If it is
fully implemented in the subclass, there is nothing 'fascistic' about
wanting to prevent further overrides. A subclass is, by definition, a
different object than its base class; overriding base class features is
the whole point of a derived class.

I don't have much C++ experience, so what I'm about to describe may be
poorly designed. I designed it shortly after I first learned about C++,
and long before I ever heard about the STL, so it may duplicate some
functionality in the STL (I still haven't finished reading that part of
the standard):

I had a Vector class, which defined non-virtual mathematical operator
overloads appropriate to mathematical vectors, but left the storage
method up to derived classes. Thus, length() and operator[]() were
virtual members, which were called by the mathematical operator
overloads.

The NVector class was derived from Vector. It had constructor which took
a length argument, which was stored in the class, and retrieved by
length(). It also stored a pointer to dynamically allocated storage for
the vector.

The ThreeVector class implemented length() as returning a constant 3. It
used a fixed double[3] array member to store the data. Thus, it was
quicker, smaller, but less flexible than an NVector.

I cannot think any situation where it would be a good idea for a class
derived from ThreeVector to override length(). If there were a 'final'
keyword in C++, I would have used it there.

Do you think I would have been wrong to do so, or would you say that
there is a design error here?
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Mark Wilden <Mark@mWilden.com>
Date: 1997/09/11
Raw View
Colin Rafferty wrote:
>
> That is exactly my point.  It is fascistic for a subclass designer to
> override the design of the base class designer.

I'd say the exact opposite (or perhaps you meant to, as well?).
The subclasser has to use the baseclasser's code, but not the other way
around. Therefore the baseclasser should usually not seek to predict
every possible way the class could be subclassed, and instead permit
flexibility where not absolutely semantically invalid.
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: "Cristian Georgescu" <Cristian.Georgescu@worldnet.att.net>
Date: 1997/09/11
Raw View
Colin Rafferty <craffert@ml.com> wrote in article
<ocr4t7tgprf.fsf@ml.com>...
> Cristian Georgescu writes:
> > Consider an Apple base class with a getColor() virtual function. Then I
> > have a YellowApple class derived from Apple, and the getColor()
overridden
> > to return the color Yellow.
>
> > The idea is that I do not want the classes that inherit from
YellowApple to
> > override the getColor().
>
> You certainly do.  If I define LightYellowApple, I would want the
> getColor() to return an instance of LightYellow (derived from Yellow).

This was not my point. Color is an enumeration.
Yor next remark states better what I meant:

> On the other hand, if the Color attribute is a choice out of a static
> list, then there is no good reason for getColor() to be virtual in the
> base class -- it should be just returning an attribute.

I think that there is a good reason for getColor() to be virtual in the
base class:

class Apple {
public:
  enum Color {red, yellow, green};

  Apple::Color getColor();
  //...
}

class YellowApple {
public:

  Apple::Color getColor(){return Apple::Yellow;};
  //..
}

The idea is that you may have an Apple with an unknown color.
You construct the Apple at night but you cannot see the color, therefore
you set the color attribute later, when you see beter.

Then, if you have something like this:

void paintApple(Apple& anApple){
  //..
  buySomePaint( anApple.getColor() );
}

and you pass an YellowApple, you just want to make sure that whoever is
buying the paint for you is buying Yellow color pain.

For the function paintApple to work well, you have to make the getColor
vitual; The example becomes:

class Apple {
public:
  enum Color {red, yellow, green};

  virtual Apple::Color getColor();
  //...
}

class YellowApple {
public:

  virtual Apple::Color getColor(){return Apple::Yellow;};
  //..
}

--
Cristian Georgescu
_________________________________________________
    Smith Industries
    Aerospace & Defense Systems
    7-9 Vreeland Road,
    Florham Park, NJ 07932, USA.
_________________________________________________
E-mail: Georgescu_Christian@si.com
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/09/11
Raw View
Valentin Bonnard <bonnardv@pratique.fr> writes:

>Colin Rafferty <craffert@ml.com> writes:
>
>> Michael B Taylor writes:
>>
>> > Maybe I missing something about this whole thread, but it seems to me that
>> > the desire to declare a virtual method "final" in some derived class is the
>> > same as the desire to declare a method in a class non-virtual.
>> > [[...Example defining a class `foo' by inheriting from a class `bar'
>> > which has a virtual member `spam()'...]]
>> > I'm forced to have spam virtual.
>>
>> You are only forced into doing this because you have derived from
>> `bar'.  This is your choice.  Since `foo' "is-a" `bar', then it must
>> have all the same properties of `bar'.  One of these is that its member
>> function `spam' is overridable by subclasses.
>
>You invented a new substitution principle (the Rafferty
>substitution principle ?); I never saw it in OO litterature.

As in Rafferty's Rules? ;-)

This principle would make sense only in a language in which you could
dynamically create subclasses of a dynamically chosen class at runtime.
In that case, it would be an instance of the Liskov substitution
principle.  C++ does not allow that sort of dynamic behaviour.

Even in a hypothetical language C+=42 that did allow such dynamic class
creation and runtime derivation, the principle would not always apply.
If you're using private inheritence, then that the fact that
`foo' "is-a" `bar' is private, and so classes derived from `foo'
should not be able to take advantage of that.

--
Fergus Henderson <fjh@cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3         |     -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1997/09/11
Raw View
Christian Millour wrote:
>
> Steve Clamage wrote:
> >
> > Cristian Georgescu wrote:
> > >
> > > The problem with 1. is that you may need a certain function to be virtual
> > > through the class hierachy inside your code, but you would like that in a
> > > certain leaf class (that is intended to be used by the user) the user
> > > should not override the virtual function.
> >
> > But why?
> >
>
> I run into this problem everytime I attempt to nest `template methods'
> (see `Design Patterns' p 325), as in:
>
> class Queryable {
>   ...
> public:
>   // template method
>   void query(Whatever & into) { do_query(into); }
> private:
>   // hook
>   virtual void do_query(Whatever & into) = 0;
> };
>
> class Cached : public Queryable {
>   ...
> private:
>   // now the hook becomes itself a template method
>   virtual void do_query(Whatever & into) {
>     if (expired()) { renovate_cache(); expired(false); }
>     copy_cache(into);
>   }
>   // hooks
>   virtual void renovate_cache() = 0;
>   virtual void copy_cache(Whatever & into) = 0;
> };
>
> classes derived from Cached should implement `renovate_cache'
> and `copy_cache' but should not override `do_query', whose
> job is done for good. Arguably, a derived class might extend
> do_query (provided it was made protected rather than private)
> as
>
> void DerivedFromCached::do_query(Whatever & into) {
>   // before stuff
>   Cached::do_query(into);
>   // after stuff
> }
>
> but any other form is likely to compromise Cached's semantics,
> which is rather distressing.
>
> So maybe the design is wrong. But what are the alternatives ?

Maybe, instead of a keyword "final", we should have a keyword
like "force_call", which makes it an error not to call the base
class function when overriding it.
The force_call modifier should be allowed to be added for
overriding functions, but not to be removed (although it may
be omitted, just like virtual).

For example, your Cached class could define

virtual force_call void do_query(Whatever& into)

and thus ensure that every derived class must use this code
even if it overrides the function (i.e. it can add things to it,
but it can't replace it).

For example, the following would possibly be reasonable:

class ConditionallyCached: public Cached
{
private:
  virtual force_call void do_query(Whatever& info)
    {
      Cached::do_query(info);
      if(info.no_caching())
        expired(true);
    }
};

Of course, even with force_call, you could decide not to call
the overriden function by simply doing:

class Machiavelli: public Cached
{
private:
  virtual force_call void do_query(Whatever& info)
    {
      if(0) Cached::do_query(info); // trick the compiler
      info=Whatever("Never ask me.");
    }
};

But we know, C++ is not intended to protect against Machiavelli :-)
(BTW, such a class might even be useful for debugging!)
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Colin Rafferty <craffert@ml.com>
Date: 1997/09/11
Raw View
James Kuyper writes:
> Colin Rafferty wrote:
>> In article <5v1i5j$qrg$1@mail.pl.unisys.com>, Brett writes:

>> > Personally, I think that a function should almost never be defined final
>> > because it cancels out much of the usefulness of object-oriented code design.
>> > I want to be able to extend and modify my classes as much as possible.

>> That is exactly my point.  It is fascistic for a subclass designer to
>> override the design of the base class designer.

> I don't have much C++ experience, so what I'm about to describe may be
> poorly designed. I designed it shortly after I first learned about C++,
> and long before I ever heard about the STL, so it may duplicate some
> functionality in the STL (I still haven't finished reading that part of
> the standard):

> I had a Vector class, which defined non-virtual mathematical operator
> overloads appropriate to mathematical vectors, but left the storage
> method up to derived classes. Thus, length() and operator[]() were
> virtual members, which were called by the mathematical operator
> overloads.

I would say that the design could be improved.  The storage method is an
attribute of the Vector, not the behavior.  As someone else pointed out,
only behavior should be virtual; attributes should is passed to the
constructor, or  specialized in a template.

The class `std::vector' is a perfect example of this.  Rather than only
being templated on the type of the contained object, it is also
templated on the allocator.

Doing it this way gives the ability to use the same allocation scheme in
multiple collections (not just your Vector), and avoids a "combinatorial
explosion of subclasses"[1].

> The ThreeVector class implemented length() as returning a constant 3. It
> used a fixed double[3] array member to store the data. Thus, it was
> quicker, smaller, but less flexible than an NVector.

> I cannot think any situation where it would be a good idea for a class
> derived from ThreeVector to override length(). If there were a 'final'
> keyword in C++, I would have used it there.

This is a little goofy, but it would work:

   template <class TT>
   class FiveVector : public ThreeVector<TT> {
         TT rest_[2];
      public:
         virtual size_t length() const { return ThreeVector<TT>::length() + 2; }
         virtual TT& ref(size_t elt) {
            return ((elt < 2) ? rest_[elt] : ThreeVector<TT>::ref(elt - 2));
         }
   };

More practically, if you wanted to do some logging, that might be
reasonable as well:

   template <class TT>
   class LoggingVector : public ThreeVector<TT> {
      public:
         virtual size_t length() const {
            cout << "Getting length again." << endl;
            return ThreeVector<TT>::length();
         }
   };

Of course, the basic point is still that the allocation should be an
attribute of your Vector class itself, rather than a behavior of a
subclass.

--
Colin

Footnotes:
[1]  Mark Wilden <Mark@mwilden.com> in <34172B24.38DE@mWilden.com>.
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: "Cristian Georgescu" <Cristian.Georgescu@worldnet.att.net>
Date: 1997/09/12
Raw View
Colin Rafferty <craffert@ml.com> wrote in article
<ocrpvqfgaqw.fsf@ml.com>...
> James Kuyper writes:
> > The ThreeVector class implemented length() as returning a constant 3.
It
> > used a fixed double[3] array member to store the data. Thus, it was
> > quicker, smaller, but less flexible than an NVector.
>
> > I cannot think any situation where it would be a good idea for a class
> > derived from ThreeVector to override length(). If there were a 'final'
> > keyword in C++, I would have used it there.
>
> This is a little goofy, but it would work:
>
>    template <class TT>
>    class FiveVector : public ThreeVector<TT> {
>          TT rest_[2];
>       public:
>          virtual size_t length() const { return ThreeVector<TT>::length()
+ 2; }
>          virtual TT& ref(size_t elt) {
>             return ((elt < 2) ? rest_[elt] : ThreeVector<TT>::ref(elt -
2));
>          }
>    };

To me this does not make sense: you say that a ThreeVector is a FiveVector?
(Basically a pentagon is a triangle?)

Or rather should we read: ThreeVector<TT> as: the class ThreeVector is a
poligon?

> Of course, the basic point is still that the allocation should be an
> attribute of your Vector class itself, rather than a behavior of a
> subclass.

I suppose length IS an attribute of the class Vector as well as of the
class ThreeVector. But it is private and there is also a function
getLength() that is virtual in Vector.

The example may be not quite suitable however for the discussion because
the underlying attribute can be set as a constant in the constructor, and
there is no reason why getLength should be virtual.

But what happens if you have an invariant of the class, or an Attribute
that is computed not mapped to a variable in the class.

class Rectangle {
 double length_;
 double width_;
public:
 double Length(){return length_;}
 double Width(){return width_;}

 Rectangle(double length, double width): length_(length), width_(width){};

 virual double Area(){return length_*width_;}
 virual double AspectRatio(){return length_/width_;}
}

class Square : public Rectangle {
public:

 Square(double size): Rectangle(size, size){};

 virtual double Area(){return sqr(size);}
 virtual double AspectRatio(){return 1.0;}
}

In this case we have:

1. Square::Area() that can be seen as an algorithmic improvement of the
Rectangle::Area() in order to take into account the specificity of the
Square

This Square::Area() may be a candidate to be final.

2. Square::AspectRatio() that is an invariant of the Square with respect to
the Rectangle::AspectRatio() which is not.

This Square::AspectRatio() should be definitely a candidate to be final.

Remark:
=======
Declaring final Square::AspectRatio():

 final virtual double AspectRatio(){return 1.0;}

therefor removing the virtualness of the AspectRatio() from Square on,
would make that the classes that inherit from the Square have the
AspectRatio() function binding at compile time (with respect to class
Square) -- therefore some performance improvement! I think this may be a
good thing.

Besides, if all the functions from Square are finalized, then the classes
derived from Square would not even need a vptr table.

--
Cristian Georgescu
_________________________________________________
    Smith Industries
    Aerospace & Defense Systems
    7-9 Vreeland Road,
    Florham Park, NJ 07932, USA.
_________________________________________________
E-mail: Georgescu_Christian@si.com
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Cristian Georgescu" <Cristian.Georgescu@worldnet.att.net>
Date: 1997/09/12
Raw View
Colin Rafferty <craffert@ml.com> wrote in article
<ocrpvqfgaqw.fsf@ml.com>...
> James Kuyper writes:
> > The ThreeVector class implemented length() as returning a constant 3.
It
> > used a fixed double[3] array member to store the data. Thus, it was
> > quicker, smaller, but less flexible than an NVector.
>
> > I cannot think any situation where it would be a good idea for a class
> > derived from ThreeVector to override length(). If there were a 'final'
> > keyword in C++, I would have used it there.
>
> This is a little goofy, but it would work:
>
>    template <class TT>
>    class FiveVector : public ThreeVector<TT> {
>          TT rest_[2];
>       public:
>          virtual size_t length() const { return ThreeVector<TT>::length()
+ 2; }
>          virtual TT& ref(size_t elt) {
>             return ((elt < 2) ? rest_[elt] : ThreeVector<TT>::ref(elt -
2));
>          }
>    };

To me this does not make sense: you say that a ThreeVector is a FiveVector?
(Basically a pentagon is a triangle?)

Or rather should we read: ThreeVector<TT> as: the class ThreeVector is a
poligon?

> Of course, the basic point is still that the allocation should be an
> attribute of your Vector class itself, rather than a behavior of a
> subclass.

I suppose length IS an attribute of the class Vector as well as of the
class ThreeVector. But it is private and there is also a function
getLength() that is virtual in Vector.

The example may be not quite suitable however for the discussion because
the underlying attribute can be set as a constant in the constructor, and
there is no reason why getLength should be virtual.

But what happens if you have an invariant of the class, or an Attribute
that is computed not mapped to a variable in the class.

class Rectangle {
 double length_;
 double width_;
public:
 Length(){return length_;}
 Width(){return width_;}

 Rectangle(double length, double width): length_(length), width_(width){};

 virual double Area(){return length_*width_;}
 virual double AspectRatio(){return length_/width_;}
}

class Square : public Rectangle {
public:

 Square(double size): Rectangle(size, size){};

 virtual double Area(){return sqr(size);}
 virtual double AspectRatio(){return 1.0;}
}

In this case we have:

1. Square::Area() that can be seen as an algorithmic improvement of the
Rectangle::Area() in order to take into account the specificity of the
Square

This Square::Area() may be a candidate to be final.

2. Square::AspectRatio() that is an invariant of the Square with respect to
the Rectangle::AspectRatio() which is not.

This Square::AspectRatio() should be definitely a candidate to be final.

Remark:
=======
Declaring final Square::AspectRatio():

 final virtual double AspectRatio(){return 1.0;}

therefor removing the virtualness of the AspectRatio() from Square on,
would make that the classes that inherit from the Square have the
AspectRatio() function binding at compile time (with respect to class
Square) -- therefore some performance improvement! I think this may be a
good thing.

Besides, if all the functions from Square are finalized, then the classes
derived from Square would not even need a vptr table.

--
Cristian Georgescu
_________________________________________________
    Smith Industries
    Aerospace & Defense Systems
    7-9 Vreeland Road,
    Florham Park, NJ 07932, USA.
_________________________________________________
E-mail: Georgescu_Christian@si.com
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: James Kuyper <kuyper@wizard.net>
Date: 1997/09/12
Raw View
Colin Rafferty wrote:
>
> James Kuyper writes:
> > Colin Rafferty wrote:
> >> In article <5v1i5j$qrg$1@mail.pl.unisys.com>, Brett writes:
>
> >> > Personally, I think that a function should almost never be defined final
> >> > because it cancels out much of the usefulness of object-oriented code design.
> >> > I want to be able to extend and modify my classes as much as possible.
>
> >> That is exactly my point.  It is fascistic for a subclass designer to
> >> override the design of the base class designer.
>
> > I don't have much C++ experience, so what I'm about to describe may be
> > poorly designed. I designed it shortly after I first learned about C++,
> > and long before I ever heard about the STL, so it may duplicate some
> > functionality in the STL (I still haven't finished reading that part of
> > the standard):
>
> > I had a Vector class, which defined non-virtual mathematical operator
> > overloads appropriate to mathematical vectors, but left the storage
> > method up to derived classes. Thus, length() and operator[]() were
> > virtual members, which were called by the mathematical operator
> > overloads.
>
> I would say that the design could be improved.  The storage method is an
> attribute of the Vector, not the behavior.  As someone else pointed out,
> only behavior should be virtual; attributes should is passed to the
> constructor, or  specialized in a template.
>
> The class `std::vector' is a perfect example of this.  Rather than only
> being templated on the type of the contained object, it is also
> templated on the allocator.
>
> Doing it this way gives the ability to use the same allocation scheme in
> multiple collections (not just your Vector), and avoids a "combinatorial
> explosion of subclasses"[1].

I'm still learning about templates. Ideally, I would like to have many
different mathematical vector classes, with many different element types
and storage methods, which can be added, subtracted, or multiplied
freely with each other. The expression (vec1+vec2), where 'vec1' and
'vec2' are both mathematical vectors, should return a vector using the
same storage method as vec1, and an element type that is the same as
that returned by vec1[0]+vec2[0]. The code that does the vector
additions should be part of MathVector, and kept distinct from the code
that implements the different storage methods. How closely can this
ideal be achieved?

I'm undecided about the correct way to handle length mis-matches. One
alternative is to treat the shorter vector as if it had 0's appended.
Another alternative is to raise an exception. A third possibility is to
return a static empty ErrorVector object. The first method is the
simplest, but provides no way to detect the error.

>
> > The ThreeVector class implemented length() as returning a constant 3. It
> > used a fixed double[3] array member to store the data. Thus, it was
> > quicker, smaller, but less flexible than an NVector.
>
> > I cannot think any situation where it would be a good idea for a class
> > derived from ThreeVector to override length(). If there were a 'final'
> > keyword in C++, I would have used it there.
>
> This is a little goofy, but it would work:
>
>    template <class TT>
>    class FiveVector : public ThreeVector<TT> {
>          TT rest_[2];
>       public:
>          virtual size_t length() const { return ThreeVector<TT>::length() + 2; }
>          virtual TT& ref(size_t elt) {
>             return ((elt < 2) ? rest_[elt] : ThreeVector<TT>::ref(elt - 2));
>          }
>    };

Yes, that is very goofy. It illustrates my point. Why derive FiveVector
from ThreeVector, rather than deriving it directly from Vector?

>
> More practically, if you wanted to do some logging, that might be
> reasonable as well:
>
>    template <class TT>
>    class LoggingVector : public ThreeVector<TT> {
>       public:
>          virtual size_t length() const {
>             cout << "Getting length again." << endl;
>             return ThreeVector<TT>::length();
>          }
>    };

This is a more relevant example, but it has nothing to do with the fact
that Vector::length() was virtual. and overriden by
ThreeVector::length(). You could equal well want to add logging to
operator+(), which was not virtual at any level. You examples implies
that all methods should always be virtual, to allow derived classes to
add arbitrary features to them.
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: "Cristian Georgescu" <Cristian.Georgescu@worldnet.att.net>
Date: 1997/09/12
Raw View
Fergus Henderson <fjh@mundook.cs.mu.OZ.AU> wrote in article
<5v719t$7g1@mulga.cs.mu.OZ.AU>...
> Even in a hypothetical language C+=42 that did allow such dynamic class
> creation and runtime derivation, the principle would not always apply.
> If you're using private inheritence, then that the fact that
> `foo' "is-a" `bar' is private, and so classes derived from `foo'
> should not be able to take advantage of that.
>

You can override a virtual private function from the base class.
But this is another problem.


--
Cristian Georgescu
_________________________________________________
    Smith Industries
    Aerospace & Defense Systems
    7-9 Vreeland Road,
    Florham Park, NJ 07932, USA.
_________________________________________________
E-mail: Georgescu_Christian@si.com
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Colin Rafferty <craffert@ml.com>
Date: 1997/09/12
Raw View
Cristian Georgescu writes:
> Colin Rafferty <craffert@ml.com> wrote:
>> Cristian Georgescu writes:

>> > Consider an Apple base class with a getColor() virtual
>> > function. Then I have a YellowApple class derived from Apple, and
>> > the getColor() overridden to return the color Yellow.
>>
>> > The idea is that I do not want the classes that inherit from
>> > YellowApple to override the getColor().
>>
>> You certainly do.  If I define LightYellowApple, I would want the
>> getColor() to return an instance of LightYellow (derived from Yellow).

> This was not my point. Color is an enumeration.

I just wanted to cover all the possible bases.

> Yor next remark states better what I meant:

>> On the other hand, if the Color attribute is a choice out of a static
>> list, then there is no good reason for getColor() to be virtual in the
>> base class -- it should be just returning an attribute.

> I think that there is a good reason for getColor() to be virtual in the
> base class:

> class Apple {
> public:
>   enum Color {red, yellow, green};

>   Apple::Color getColor();
>   //...
> }

> class YellowApple {
> public:

>   Apple::Color getColor(){return Apple::Yellow;};
>   //..
> }

Since color is just an attribute, you don't need a virtual function.
All you need is a constructor with the color as an argument.

class Apple {
public:
  enum Color {red, yellow, green};

  Apple(..., Color color) : color_(color), ... { ... }

  Color getColor() const { return color_; }

  // ...
};

class YellowApple : public Apple {
public:
  YellowApple(...) : Apple(..., yellow) { ... }
  // ...
};


If all that you want the subclass to define is one out of a fixed range
of choices, you don't want virtual functions in the first place.  If the
range can be expanded, or you want the subclass to define behavior, then
the `final' keyword becomes just an impediment to a useful hierarchy.

> The idea is that you may have an Apple with an unknown color.
> You construct the Apple at night but you cannot see the color, therefore
> you set the color attribute later, when you see beter.

In the case where you must change the attibute after construction, you
would have a protected function, Apple::setColor.

--
#!/bin/perl -sp0777i<X+d*lMLa^*lN%0]dsXx++lMlN/dsM0<j]dsj
$/=unpack('H*',$_);$_=`echo 16dio\U$k"SK$/SM$n\EsN0p[lN*1
lK[d2%Sa2/d0$^Ixp"|dc`;s/\W//g;$_=pack('H*',/((..)*)$/)
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Colin Rafferty <craffert@ml.com>
Date: 1997/09/05
Raw View

Michael B Taylor writes:

> Maybe I missing something about this whole thread, but it seems to me that
> the desire to declare a virtual method "final" in some derived class is the
> same as the desire to declare a method in a class non-virtual.

> Say I'm designing a class foo:

> class foo
> {
> public:
>     int spam();
> };

> Making spam non-virtual seems perfectly reasonable.

> However, in this case

> class bar
> {
> public:
>     virtual int spam(); // maybe even: = 0
> };

> class foo : public bar
> {
> public:
>  int spam();
> };

> I'm forced to have spam virtual.

You are only forced into doing this because you have derived from
`bar'.  This is your choice.  Since `foo' "is-a" `bar', then it must
have all the same properties of `bar'.  One of these is that its member
function `spam' is overridable by subclasses.

If you don't like this behavior, then you shouldn't be deriving from
`bar' in the first place.

I think the point is that there is no good reason for wanting `final',
and lots of bad reasons.

Steve Clamage gave a lucid example of why this is a bad idea.  I have
yet to see an example of why this is useful.  I cannot imagine a
real-life use for `final', other than due to a poorly designed base
class.

--
Colin Rafferty
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Cristian Georgescu" <Cristian.Georgescu@worldnet.att.net>
Date: 1997/09/08
Raw View
> I think the point is that there is no good reason for wanting `final',
> and lots of bad reasons.
>
> Steve Clamage gave a lucid example of why this is a bad idea.  I have
> yet to see an example of why this is useful.  I cannot imagine a
> real-life use for `final', other than due to a poorly designed base
> class.
>
> --
> Colin Rafferty
> ---

Consider an Apple base class with a getColor() virtual function. Then I
have a YellowApple class derived from Apple, and the getColor() overridden
to return the color Yellow.

The idea is that I do not want the classes that inherit from YellowApple to
override the getColor().


--
Cristian Georgescu
_________________________________________________
    Smith Industries
    Aerospace & Defense Systems
    7-9 Vreeland Road,
    Florham Park, NJ 07932, USA.
_________________________________________________
E-mail: Georgescu_Christian@si.com
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Gerard Weatherby <gerardw@alum.mit.edu>
Date: 1997/09/08
Raw View

Steve Clamage <stephen.clamage@eng.sun.com> wrote:
----------------

Cristian Georgescu wrote:
>
> Is there a way to specify that a virtual function should not be overridden
> anymore?

No.

> In the case there is no way to do this, maybe there is a need of a special
> keyword (final?) to specify this?

You are saying that it is OK for other programmers to derive from
your class for their own purposes, but you somehow know that no
matter what they are doing, they must not override that particular
virtual function.

How in the world can you know that?

It seems to me that more sensible choices are
1. don't make the function virtual, or
2. make the function private, or
3. make it impossible to derive from the class at all.

Choice 3 is a bit tricky, and is sometimes used as a C++ puzzle,
as if C++ needed puzzles. (Stop reading now if you don't want
to be told the answer.)

Solution:

Give your class a private virtual base class of which your class
is a friend. Derived classes would need to invoke the virtual
base class constructor, but don't have access.

------------------------
Option 1 may not work.  2 doesn't work, as the function can still be
overriden.
How can you say 3 is tricky? Anyone who reads the newsgroup has
obviously read the FAQ at the bottom of every message. The FAQ, in turn,
refers to the Design and Evolution book which clearly documents this
technique...

To answer the question "Is there a way to specify that a virtual
function should not be overridden anymore?"


1. As noted by other respondents, what you're doing seems weird and
probably not a really good design...

2. But since you didn't ask that, the answer is "No, but you can get the
effect if you work hard enough."

Assume you want to provide hierachy A, B, and C (B derives from A, C
derives from B) with a virtual function you want to override, but not
let any user class U that derives from C (or B or A) override it.

To get this effect, implement the hierachy using the "Cheshire-cat"
technique and make the function virtual in the implementing class.

HEADER FILE
class A_impl;
class A {
 public:
  A( );
  virtual ~A( );
  int finalFunction( );
 protected:
  A(A_impl *i):impl(i) {}
 private:
  A_impl *impl;
};

class B : public A {
 public:
  B( );
 protected:
  B(A_impl *i):A(i) {}
};

class C : public B { ...same stuff...

SOURCE FILE
class A_impl {
 public:
  A_impl( ) {...}
  virtual ~A_impl( );
  virtual int finalFunctionImpl( );
};

class B_impl : public A_impl {
 public:
  B_impl( ) {...}
  virtual ~B_impl( );
  virtual int finalFunctionImpl( );
};

class C_impl : public B_impl { ...same stuff...

A::A( ):impl(new A_impl) {}
A::~A( ) { delete impl; }
int A::finalFunction { return impl->finalFunction( ); }

B::B( ):A(new B_impl) {}
...

So the function is virtual to the implementer of A, B, and C, because
it's virtual in the implementation hierachy.  To the user of the class
hierachy, it's not virtual (just an ordinary function on class A), and
the actual virtual function can't be overridden because the definition
of A_impl is hidden in a source file.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Cristian Georgescu" <Cristian.Georgescu@worldnet.att.net>
Date: 1997/09/08
Raw View

> OK, I find your class useful, I add some functionality to Base,
> including some additional data members, and create class Derived.
> In order to preserve the correct semantics of "f", it must have
> additional effects on some new members of Derived. To achieve that,
> I must override f. The overriding function calls Base::f then
> performs its own actions. (In general, that is the correct way
> to override a virtual function.)
>
> Again I ask: Why?
>

Suppose you have a class Apple with a virtual function getColor(); then I
want to make a derived class GreenApple with getColor that will always
return Green.
You may inherit from GreenApple, and possibly override other virtual
functions (like getPrice() ), but I do not like that you override
getColor() !

>
> But now you add the criterion that I must not be allowed to do
> what is essential to allow my derived class to work.
>

Making the getColor() method final (not overridable) for YellowApple class
is essential to the semantics of the class. Therefore you are not supposed
to modify it. Ideally this should not beven be a virual function. It just
is so, because YellowApple has a base class where the getColor() is
virtual.

Bootom line is:

- either the language should require you to put the "virtual keyword each
time
- or the laguage defaults a function virtual in the derived classes, but
should provide a way to terminate this!


--
Cristian Georgescu
_________________________________________________
    Smith Industries
    Aerospace & Defense Systems
    7-9 Vreeland Road,
    Florham Park, NJ 07932, USA.
_________________________________________________
E-mail: Georgescu_Christian@si.com
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: brett.ger-ry@uni-sys.com (Brett)
Date: 1997/09/08
Raw View
In article <ocr4t7zlk2o.fsf@ml.com>, Colin Rafferty <craffert@ml.com> wrote:
<SNIP>
>
>Steve Clamage gave a lucid example of why this is a bad idea.  I have
>yet to see an example of why this is useful.  I cannot imagine a
>real-life use for `final', other than due to a poorly designed base
>class.
>

Have you taken a look at the Java 1.02 API?  I think the number of virutal
functions that are eventually defined final in a derived class number in the
hundreds.

Personally, I think that a function should almost never be defined final
because it cancels out much of the usefulness of object-oriented code design.
I want to be able to extend and modify my classes as much as possible.


-Brett

**********************************************************
* For e-mail replies omit all dashes from the            *
* address in the "From: " field.                         *
**********************************************************
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: "Michael B. Taylor" <mbtaylor@microsoft.com>
Date: 1997/09/08
Raw View

Colin Rafferty <craffert@ml.com> wrote in article
<ocr4t7zlk2o.fsf@ml.com>...
> I think the point is that there is no good reason for wanting `final',
> and lots of bad reasons.
>
> Steve Clamage gave a lucid example of why this is a bad idea.  I have
> yet to see an example of why this is useful.  I cannot imagine a
> real-life use for `final', other than due to a poorly designed base
> class.

I agree Steve's example was lucid. However, I think it could be equally
well applied to any member function.

Personally I have never needed nor wanted final, but I don't see any reason
why it shouldn't exist. If it is reasonable to make class methods
non-virtual, it seems equally reasonable to remove the virtualness of a
base classes members.
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Barry Margolin <barmar@bbnplanet.com>
Date: 1997/09/08
Raw View
In article <5ut97j$nkr@bgtnsc02.worldnet.att.net>,
Cristian Georgescu <Cristian.Georgescu@worldnet.att.net> wrote:
>The idea is that I do not want the classes that inherit from YellowApple to
>override the getColor().

Why do you want to prevent someone from implementing a DecayedYellowApple
subclass?

--
Barry Margolin, barmar@bbnplanet.com
GTE Internetworking, Powered by BBN, Cambridge, MA
Support the anti-spam movement; see <http://www.cauce.org/>
Please don't send technical questions directly to me, post them to newsgroups.
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: lippin@zocalo.net (Tom Lippincott)
Date: 1997/09/09
Raw View
Cristian Georgescu wrote:
>
> Is there a way to specify that a virtual function should not be overridden
> anymore?
>
> In the case there is no way to do this, maybe there is a need of a special
> keyword (final?) to specify this?

Steve Clamage <stephen.clamage@eng.sun.com> replied:

> No.
[...]
> It seems to me that more sensible choices are
> 1. don't make the function virtual, or
> 2. make the function private, or
> 3. make it impossible to derive from the class at all.

It's my understanding that choice 2 won't work: a class need not have
access to a virtual function in order to override it.  Has this changed?

I've always thought this was an unfortunate hole in the access rules,
because of this awkward situation:

class A { some virtual members };
class B : private A { ... };
class C : public B { ... };

The author of C needs to be aware of B's inheritance from A, and needs to
know the virtual functions of A, so that C won't accidentally override
them.  Likewise, one cannot add a private base class to B without the danger
that a formerly non-virtual member of C will become virtual, or be called
at unexpected times.

A comment in the ARM (11.6) suggests:
> Private virtual functions provide a way for the implementation of a
> base class to rely on derived classes without the functions involved
> being exposed to the general users of the base class.

I haven't been able to come up with an example along these lines
which isn't adequately served by making the virtual function protected.

Given my druthers, I'd change the language to disallow overriding a
member to which one does not have access.  Were I designing a new language,
I'd consider using a syntax in which the overriding function must explicitly
name the function it overrides:

   virtual void Foo() overrides X::Foo;

                                          --Tom Lippincott
                                            lippin@zocalo.net

  "Many are happy much of the time; more eat than starve, more are healthy
   than sick, more curable than dying, not so many dying as dead; and one
   of the thieves was saved."
                                --Tom Stoppard, _Jumpers_
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/09/09
Raw View
Barry Margolin <barmar@bbnplanet.com> writes:

>Cristian Georgescu <Cristian.Georgescu@worldnet.att.net> wrote:
>>The idea is that I do not want the classes that inherit from YellowApple to
>>override the getColor().
>
>Why do you want to prevent someone from implementing a DecayedYellowApple
>subclass?

Because if they do, it may cause later maintenance difficulties.

There's nothing wrong with the idea of a DecayedYellowApple class,
but making it a subclass of YellowApple may be a bad idea, if
it is not yellow.  Using inheritence even when the "is-a" relation
doesn't hold is often bad design.

One problem is that someone may add new member functions such as
nutritional_value() to the Apple class, and the DecayedYellowApple may
inherit the definitions of these from the new YellowApple class, even
though those definitions are not appropriate.

Another problem is that there may be code that assumes
if `dynamic_cast<YellowApple*>(p)', then `p' points to a yellow apple.
(Even if there isn't any such code now, then there may be in the future.)

--
Fergus Henderson <fjh@cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3         |     -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/09/10
Raw View
Newsgroup: comp.std.c++

Colin Rafferty <craffert@ml.com> writes:

> Michael B Taylor writes:
>
> > Maybe I missing something about this whole thread, but it seems to me that
> > the desire to declare a virtual method "final" in some derived class is the
> > same as the desire to declare a method in a class non-virtual.
>
> > Say I'm designing a class foo:
>
> > class foo
> > {
> > public:
> >     int spam();
> > };
>
> > Making spam non-virtual seems perfectly reasonable.
>
> > However, in this case
>
> > class bar
> > {
> > public:
> >     virtual int spam(); // maybe even: = 0
> > };
>
> > class foo : public bar
> > {
> > public:
> >  int spam();
> > };
>
> > I'm forced to have spam virtual.
>
> You are only forced into doing this because you have derived from
> `bar'.  This is your choice.  Since `foo' "is-a" `bar', then it must
> have all the same properties of `bar'.  One of these is that its member
> function `spam' is overridable by subclasses.

You invented a new substitution principle (the Rafferty
substitution principle ?); I never saw it in OO litterature.

> If you don't like this behavior, then you shouldn't be deriving from
> `bar' in the first place.
>
> I think the point is that there is no good reason for wanting `final',
> and lots of bad reasons.

There are bad reasons for wanting everything in C++, and for wanting
to program in C++.

> Steve Clamage gave a lucid example of why this is a bad idea.  I have
> yet to see an example of why this is useful.  I cannot imagine a
> real-life use for `final', other than due to a poorly designed base
> class.

When you merge derive from two independant classes (say A and B)
which define the same virtual function (say draw), you might want
to overide A::draw and B::draw as their meaning is independant.

To do that you define two forwarding functions in two classes,
AdaptA and AdaptB (everydoby here knows this trick); I don't
see any reasons not to declare the forwarding functions virtual.

Others might find additionnal examples.

--

Valentin Bonnard
mailto:bonnardv@pratique.fr
http://www.pratique.fr/~bonnardv (Informations sur le C++ en Francais)
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Mike Davies <mike_davies@noco.demon.co.uk>
Date: 1997/09/10
Raw View
In article <5v232a$jot@tools.bbnplanet.com>, Barry Margolin
<barmar@bbnplanet.com> writes
>In article <5ut97j$nkr@bgtnsc02.worldnet.att.net>,
>Cristian Georgescu <Cristian.Georgescu@worldnet.att.net> wrote:
>>The idea is that I do not want the classes that inherit from YellowApple to
>>override the getColor().
>
>Why do you want to prevent someone from implementing a DecayedYellowApple
>subclass?
>

He doesn't, he wants a DecayedYellowApple to be distinguished from a
DecayedRedApple in the exact same manner that a YellowApple is
distinguished from a RedApple.


--
Age has taught me one thing :
Being old is shit
Mike Davies
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Colin Rafferty <craffert@ml.com>
Date: 1997/09/10
Raw View
Cristian Georgescu writes:
> Colin Rafferty writes:

>> I think the point is that there is no good reason for wanting `final',
>> and lots of bad reasons.

>> Steve Clamage gave a lucid example of why this is a bad idea.  I have
>> yet to see an example of why this is useful.  I cannot imagine a
>> real-life use for `final', other than due to a poorly designed base
>> class.

> Consider an Apple base class with a getColor() virtual function. Then I
> have a YellowApple class derived from Apple, and the getColor() overridden
> to return the color Yellow.

> The idea is that I do not want the classes that inherit from YellowApple to
> override the getColor().

You certainly do.  If I define LightYellowApple, I would want the
getColor() to return an instance of LightYellow (derived from Yellow).

On the other hand, if the Color attribute is a choice out of a static
list, then there is no good reason for getColor() to be virtual in the
base class -- it should be just returning an attribute.

--
Colin
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: "Cristian Georgescu" <Cristian.Georgescu@worldnet.att.net>
Date: 1997/09/10
Raw View

> I've always thought this was an unfortunate hole in the access rules,
> because of this awkward situation:
>
> class A { some virtual members };
> class B : private A { ... };
> class C : public B { ... };
>
> The author of C needs to be aware of B's inheritance from A, and needs to
> know the virtual functions of A, so that C won't accidentally override
> them.  Likewise, one cannot add a private base class to B without the
danger
> that a formerly non-virtual member of C will become virtual, or be called
> at unexpected times.
>                                           --Tom Lippincott

I fully agree:

IMO the logical encapsulation of a class should consist in the separation
of the class interface from the class implementation: the user should be
able to use the class by looking only to the public and to the private
parts of the class; he should not be obliged to peep to the private parts
of the base class in order to use the class.

C++ does not achieve very well this logical encapsulation; the .h files are
obliged to contain the private parts as well: in order to fully specify the
class storage.

> A comment in the ARM (11.6) suggests:
> > Private virtual functions provide a way for the implementation of a
> > base class to rely on derived classes without the functions involved
> > being exposed to the general users of the base class.

What is worse is that usually the private parts of a base class are
considered "Implementation" details; and therefore they are supposed to
change.

If the client bases the code on the use of a private virtual base class
function (by overridding it) then when this function will change (as it may
be because the function is private) then the end of the world comes (for
the user): user code has to change!

In my opinion what ARM (11.6) suggests as possible, should never be used.

> I haven't been able to come up with an example along these lines
> which isn't adequately served by making the virtual function protected.
>
>                                           --Tom Lippincott

I fully agree with this also;

Probably overriding private virtual functions should be banished from the
language. In fact I would go even further, I would interdict the
declaration of the virtual functions in the private part of the class:
virtual functions should be allowed in the protected and public part of a
class only!


--
Cristian Georgescu
_________________________________________________
    Smith Industries
    Aerospace & Defense Systems
    7-9 Vreeland Road,
    Florham Park, NJ 07932, USA.
_________________________________________________
E-mail: Georgescu_Christian@si.com
E-mail: Cristian.Georgescu@worldnet.att.net
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: "Cristian Georgescu" <Cristian.Georgescu@worldnet.att.net>
Date: 1997/09/10
Raw View
> Personally, I think that a function should almost never be defined final
> because it cancels out much of the usefulness of object-oriented code
design.
> I want to be able to extend and modify my classes as much as possible.
>
>
> -Brett
>

Suppose you have a class Apple with a virtual function getColor(); then I
want to make a derived class GreenApple with getColor that will always
return Green.

You may inherit from GreenApple, and possibly override other virtual
functions (like getPrice() ), but it does not make sense that you override
getColor() ! Because in the class Apple the getColor() returns a variable
color,
whereas in the class GreenApple the getColor() returns a (logic) constant
color.

Making the getColor() method final (not overridable) for GreenApple class
is essential to the semantics of the class. Therefore you are not supposed
to modify it. Ideally this should not be even be a virual function. It just
is so, because YellowApple has a base class where the getColor() is
virtual.

--
Cristian Georgescu
_________________________________________________
    Smith Industries
    Aerospace & Defense Systems
    7-9 Vreeland Road,
    Florham Park, NJ 07932, USA.
_________________________________________________
E-mail: Georgescu_Christian@si.com
E-mail: Cristian.Georgescu@worldnet.att.net
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Steve Clamage <stephen.clamage@eng.sun.com>
Date: 1997/08/28
Raw View
Cristian Georgescu wrote:
>
> Is there a way to specify that a virtual function should not be overridden
> anymore?

No.

> In the case there is no way to do this, maybe there is a need of a special
> keyword (final?) to specify this?

You are saying that it is OK for other programmers to derive from
your class for their own purposes, but you somehow know that no
matter what they are doing, they must not override that particular
virtual function.

How in the world can you know that?

It seems to me that more sensible choices are
1. don't make the function virtual, or
2. make the function private, or
3. make it impossible to derive from the class at all.

Choice 3 is a bit tricky, and is sometimes used as a C++ puzzle,
as if C++ needed puzzles. (Stop reading now if you don't want
to be told the answer.)

Solution:

Give your class a private virtual base class of which your class
is a friend. Derived classes would need to invoke the virtual
base class constructor, but don't have access.

--
Steve Clamage, stephen.clamage@eng.sun.com
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Cristian Georgescu" <Cristian.Georgescu@worldnet.att.net>
Date: 1997/08/25
Raw View
Is there a way to specify that a virtual function should not be overridden
anymore?

(The function is declared as virtual in the base class, and overridden in
the derived class, but I want that the classes derived from this class not
to override function anymore).

In the case there is no way to do this, maybe there is a need of a special
keyword (final?) to specify this?
--
Cristian Georgescu
_________________________________________________
    Smith Industries
    Aerospace & Defense Systems
    7-9 Vreeland Road,
    Florham Park, NJ 07932, USA.
_________________________________________________
E-mail: Georgescu_Christian@si.com
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]