Lab 10 Comp 170-201 -- Dordal/Nabicht -- Wed, November 13, 2002 Final version due In this lab you will define some classes representing shapes, with inheritance relationships between them, and then implement a draw() function for each shape. Our goal will be to illustrate the three rules: 1. Classes inherit data and, by default, functions from the parent class 2. Classes can *override* functions from the parent class, redefining them. The parent function can be called using super; thus, the parent can either be completely replaced or partly recycled. 3. Objects can be assigned to a reference of less-specific type. 4. Rule 3 notwithstanding, objects remember *their* version of any overridden functions, provided the less-specific type at least knew about that function. We start with (as usual, the file with all these is on my web page) public abstract class Shape { public void draw(Graphics g) {} public int area() {} } What this says is that every Shape object will have a draw() function, but that we're not saying anything specific about it at the moment (that last half comes from the fact that the class is "abstract"). There's no particular need for Shape in this lab; everything in fact derives from the following class: public class Rectangle extends Shape { private int _x; // left edge private int _y; // *lower* edge private int _height; private int _width; public Rectangle (int x, int y, int w, int h) { _x = x; _y = y; _width = w; _height = h; } public int area() {return _height * _width;} public void draw (Graphics g) { g.drawRect(_x, _y-_height, _width, _height); } } The applet also defines an array of Rectangles called rlist, and fills this (partly) in with a few Rectangles. Step 1: Define a class SolidRect that extends Rectangle. Add one new data field, _color, of type Color. Use g.fillRect() to draw it instead of g.drawRect. Before the call to g.fillRect(), though, use Color origColor = g.getColor() to save the "current" color, then g.setColor(_color) to set the color to the intended color, and then after drawing it restore the original color with another call to g.setColor(origColor) Note that you will have to use the Rectangle accessors x(), y(), width(), height() to get the applicable dimensions to pass to fillRect(). Be sure to remember that the y-coordinate that g.fillRect() really wants to see is y()-height(); fillRect draws from the upper left and your SolidRect should draw from the *lower* left (the same thing Rectangle does). This is an example of rule 2, with outright replacement of the draw() function. You will have a constructor public SolidRect(int x, int y, int w, int h, Color c) ... that immediately calls super(x,y,w,h) to construct the "base" rectangle, and then initializes _color with c. Step2: Define a class ColoredRect that works like SolidRect, *except* that it just draws the outline, in the selected color. In this case, you should save/set the color, and then just call the "base" draw(): super.draw(g); rather than making a new call to drawRect. This is an example of rule 2 redefining draw() by *reusing* the original draw(), in a new setting. Step 3: Add some SolidRect and ColoredRect objects to the array rlist. Note that (a) this is legal, even though rlist is an array of Rectangle, not SolidRect or ColoredRect. This is an example of rule 3 above. (b) The SolidRects and ColoredRects get drawn properly, not as plain Rectangles, even though the reference to them is as plain Rectangles. This is an example of rule 4. Step 4: Find the area() of some SolidRect and ColoredRect objects. Note that you do *not* have to redefine area() in these new classes; the area of a rectangle doesn't change if you color it or fill it in. Thus, these classes simply inherit area() from class Rectangle, without any modification. This is an example of rule 1.