Newsgroups: comp.lang.c++
Path: utzoo!utgpu!cunews!bnrgate!scrumpy!bnrmtl@bnr.ca!pat
From: pat@bnrmtl.bnr.ca (Patrick Smith)
Subject: Re: About Lists and things...
Message-ID: <1991Jun27.175256.3224@scrumpy@.bnr.ca>
Sender: news@scrumpy@.bnr.ca (USENET NEWS KJ)
Reply-To: bnrmtl!pat@larry.mcrcim.mcgill.edu
Organization: Bell Northern Research, Montreal, Canada.
References: <2865E7A8.179A@tct.com> <19131@prometheus.megatest.UUCP> <28692A4A.59B7@tct.com> <1991Jun27.095856.2@minerva.inesc.pt>
Date: Thu, 27 Jun 91 17:52:56 GMT

In article <1991Jun27.095856.2@minerva.inesc.pt>, fmhv@minerva.inesc.pt (Fernando Manuel Vasconcelos) writes:
|> In article <28692A4A.59B7@tct.com> chip@tct.com (Chip Salzenberg) writes:
|> 
|> >If you put a Circle into a ShapeList, you lose the Circle's
|> >compile-time type, because ShapeList.first() returns |Shape*|.
|> >Suppose that you decide to call a Circle-specific function on a Circle
|> >stored in a ShapeList.  Some would cast the |Shape*| to a |Circle*|
|> >and carry on.  My coding practice would require you to replace the
|> >ShapeList with a CircleList.
|> >
|> >Of course, that change may not be practical, perhaps because there are
|> >other non-Circle objects in the ShapeList.  If so, congratulations!
|> >You have just discovered that the function in question is actually a
|> >Shape function in disguise.  You should therefore add it to the Shape
|> >interface, presumably as a new virtual function.
|> >
|> >Clearer now?
|> 
|> I may be missing the point, however consider two objections to your proposal:
|> 
|> 1. A pratical one: You may not be able to change shape.h because it belongs
|> to a library which you have only in binary ( of course you have the .h's but
|> you can't change them ... )
|> 
|> 2. A conceptual one: That means the interface of a base class depends on the
|> interface of the derived classes. Using your example it is normal that a 
|> circle should know to answer it's radius. If I keep all my graphical
|> objects in a list of shapes* , I'll have to add a getRadius message to
|> the Shape class, only because a circle knows what that means ... But a GENERAL
|> shape doesn't .


I tend to agree with Chip here.  But that doesn't mean that I would
add a getRadius() method to the Shape class.  If getRadius() only
makes sense for Circles, then the only way you can use it on
an arbitrary Shape is something like this:

		if ( /* *this is a Circle */ )
			// do something with this->getRadius()
		else
			// do something else with *this
			// may be several cases - Squares, Triangles, Blobs, etc.

Even if you define getRadius() for any Shape, if it only makes
sense for Circles, you're going to get code like the above.

The style I prefer is to replace the entire if block with
a single call to a virtual function:

		this->doSomething();

Presumably, "do something" makes sense for every Shape, since
you're doing it for an arbitrary Shape you got from a ShapeList.
And then you can add appropriate member functions for each type
of Shape:

	Circle::doSomething() { /* uses this->getRadius() */ }
	Square::doSomething() { /* uses this->sideLength() */ }

etc.


If you can't change the definition of Shape (or don't want to),
you can put another class of your own in between Shape and the specific
classes:

class MyShape : public Shape { /*...*/ };
class Circle : public MyShape { /*...*/ };
class Square : public MyShape { /*...*/ };

Now you can make doSomething() a method of MyShape.

-- 
Patrick Smith      Bell-Northern Research, Montreal, Canada
(514) 765-7914   bnrmtl!pat@larry.mcrcim.mcgill.edu   patrick@bnr.ca

... Any resemblance between the above views and those of my employer,
my terminal, or the view out my window are purely coincidental.
