Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

Shapes In this quest, you get to play with inheritance and polymorphism in C++. What is polymorphism? Take a break to look up your reference

Shapes In this quest, you get to play with inheritance and polymorphism in C++. What is polymorphism? Take a break to look up your reference material now. TL;DR? Here is the abstract scoop (followed by the more concrete example which you will implement in this quest): Suppose you had many different classes, X, X, ..., that all inherited from the same base class A and that there is some method of A, say foo (), that is overridden (possibly differently) by each of its descendants. Let's say you have an array of pointers to objects of type A. Each object pointed to by this array's elements may be a different x and each x may implement its own overriding foo () according to its own specific requirements. Polymorphism lets you write code in which you can invoke foo () via a pointer to an object of type A, only to have it execute the foo () code that is attached to its derived class x, rather than the fallback-code that may be supplied with class A. I bet you're still confused. Cuz I almost done confusin meself writin that. This will help: Here is the concrete example (which you will also implement in this quest). Suppose I have a generic class called Shape (a geometric shape). There may be many different subclasses of Shape: Circle, Square, Triangle, etc. Each of these subclasses must have its own draw() method (enforced by the compiler). 'Cuz I can't draw a triangle from vertices in the same way I draw a square, yes? Polymorphism is a way that lets us invoke draw() blindly on a set of shape objects when we don't know the precise type of each object. The idea is that the system will automatically invoke the correct draw() on each object depending on the specific subclass it belongs to (Get yer eyes off the dancing octopus and look at Figure 1 already! 6 Why pointers? Can we not have an array of the objects themselves? 2 of 16 11 can to my diety v rat 1 ->draw() - Telice.... of a vele shape ->draw() ....\" site Ingle...\" ->dravo of a triangle shape wat is the ->draw() of a dress hape ->draw() - 1. star shape Figure 1: draw() is a virtual function that resolves to the appropriate derived class member function automatically Imagine the orange boves to be cells in an array of pointers to Shape objects. In this quest, you will implement many little classes. Some of these will interact with each other in fun ways (See Figure 2). A Screen class - Your canvas, on which you can paint using ASCII characters (That is, each pixel on this carwas is an ASCII character). A Shape class - The base class for all the shapes you're gonna create. In fact, we'll make it an abstract class by assigning the value 0 (the null pointer) to the method we want all subclasses to implement draw(). This empty implementation assignment tells the compiler that it is what we call a pure virtual function. Any class that subclasses (derives from) Shape MUST implement draw() or the compiler will consider that derived class also an abstract class. An abstract class cannot be instantiated because it has not yet been completely defined. The missing method implementations complete it. Then it becomes a concrete class. You can instantiate objects of a concrete class. You will also implement the following concrete subclasses of Shape: Point, Line, Quadrilateral, Upright_Rectangle and stick_Man 3 af 16 Each subclass should know how to draw itself (and not other Shapes) on a given screen using a given character. Thus each should have its own implementation of the draw() method. Shape Screen Point Line Gunderstood Slick Men Upright Rectangle Figure 2: Classes you must implement. Arrows represent inheritance. Shape is an abstract class. Its subclasses must implement draw() There's a lot you can do in this quest. Most of it is easy, but some miniquests are non-trivial. Sol would suggest this: Work on this quest until you get the password to move on. Then keep coming back to this quest to revisit skipped miniquests until the second great freeze. Your first miniquest - Screen Implement the Screen constructor: Screen:: Screen (size_t w, size_t h) It should correctly set the size of its _pix vector to have h rows and w columns. This means _pix() should end up with h vectors, each of which is w chars big. Points to keep in mind about the screen class (not necessarily to do with the constructor): Vectors at_pix[o...h-1) represent screen pixel rows o to h-1 from bottom to top. 4 of 16 The origin, (0,0). visually located at the bottom left of screens, is now the top left of the_pix vector if you imagine the vector growing downwards with row at the top. So you have to get used to flipping the image vertically as you process it (like in the eye?). Or do you need to? Your second miniquest - Fill Implement: void Screen::fill(char c) Just fill up the screen (all elements of all rows of_pix) with the supplied character.c. Your third miniquest - Clear Implement: void Screen: clear() Just fill up the screen (all elements of all rows of pix) with the background character, Screen:BG. You can simply invoke fill() from here. Hey look! I alreddy gave you this function line! Well, I guess I can't take it back now. Your fourth miniquest - To string Well, there's always a tricky one in every quest. I guess. But this doesn't have to be tricky if you remember that the bottom row of the vector is the top row of your screen and vice-versa. This is also where you might wonder if you'd have been better off mapping bottom to bottom and top to top, and then removing the corresponding adjustments from the draw methods. 5 af 16 Implement: string Screen::to_string() const It should return a string made of h newline delimited strings, each of which represents the corresponding row on a screen (line O is the top of the screen). That is, I should be able to say something like: cout ;> 2) return draw byx[ser, ch, 22, 22, x1, 1); double dy = (double) y2-31/(double) x2-x): bool contained true double xx, Y :: while x 2) contained a points, x, size drowser, ch); > return contained Figure 5. draw_by_x() Note that my draw_by_x () always draws from left to right. If my points are ordered differently, then rather than futz around with swapping values within the code, I simply make a tail-recursive invocation of the same method with swapped points. You don't have to do it this way, of course. But if you do note that the recursion overhead here is quite small and capped at one stack frame. Your eighth miniquest - Line Implement: bool Line:: draw (Screen screen, char c) Once you have the two draw_by_-0 methods done, this one is eazy peazy. All this method has to do is to determine if the line is short and fat or tall and thin, and invoke the corresponding draw_by_- () method. Discuss this in our subreddit. of 16 Remember that it must also return a boolean indicating non-overflow. You can blindly relay what your subordinate method returns to your caller. Your ninth miniquest - Quadrilateral Implement: bool Quadrilateral:: draw (Screen &screen, char c) You just have to determine the correct end points of the four lines that make this quadrilateral and draw them. In the past, I've noticed that some students put in a great deal of effort to avoid redrawing corner pixels (where the edges overlap and intersect). Let me just wish you good luck if you get sucked into that rabbit hole. Once you've established that overwriting an existing pixel with the same value is safe, you'll discover that it is a wiser choice to overwrite it than to build elaborate checks and guards. These kinds of educated tradeoffs are what come in handy as you gain more experience in programming, The Upright Rectangle A quarryshmaterell uses a lot of letters and it's hard to spell right. It also requires 4 points (and thus 8 numerical coordinates) to specify. Sure looks messy and if you're ever in a situation where the only quads you need are upright rectangles, you can simplify your life a great deal by using just 4 numbers to encode your shape - the bottom left and top right Thus was born the Upright_Rectangle. This is not a miniquest. You'll notice that the Upright_Rectangle's implementation is already completely fleshed out in the provided starter code. But you do need to know how to instantiate and use it because it is the head of the next class you need to create Nonetheless, FWIW, you get a freebie reward just for reading this section. Hooray! 10 of 16 Your tenth miniquest The Stick Man constructor Implement: Stick_Man:: Stick_Man (size_t x, size_t y, size_t w, size_t n) Imagine that your stick man is contained within a rectangular portion of a screen. Then the coordinates of the bottom left of this portion is (x, y) and its width and height are given by w and h respectively. First clear out the_parts vector and set any required member variables. Then create and push pointers to following Shapes into this vector: The stick man's head: An upright rectangle with bottom left at (x+0,y+h/2) and top right at (x+w-1, y+h-1). o Historso: A line from (x+w/2; y+h/2) to (x+w/2,y+h/4) His left arm: A line from (x+w/2, y+h/2) to (x+w/4,y+h/4) o His right arm: A line from (x+w/2,y+h/2) to (x+3*w/4, y+h/4)) His left leg: A line from (x+w/2,y+h/4) to (x,y) His right leg: A line from (x+w/2,yth/4) to (x+w-1,y) That is your stickman. Your default height is 40 and default width is 20. If the constructor is passed values of 0 or 1 for h, you should silently set it to this default height (don't worry about throwing exceptions). Likewise for w. Here is a picture of a nice little 9x20 stick man. Of course, not all stick men are nice or little never mind both! 18 19 1101 10.00 Origin Note: If the shapes you create are local to the constructor (ie. on the stack), you'll find that they're gone when the constructor exits. To make sure the shapes persist beyond the lifecycle of the constructor, they must be on the heap. This means you must delete them in your destructor or suffer memory leaks. 11 of 16 Your eleventh miniquest - Draw a Stick Man Implement: bool stick_Man::draw(Screen screen, char c) Just like the other inherited draw methods, this method should also draw its shape (in this case a Stick_Man) on the given screen using the character c. Simply invoke the draw() method on each of the objects whose pointers you can find in your parts vector. You don't have to worry about the exact type of each object because you know that everyone of those objects is a drawable object. That is, it supports a draw() method whose signature is exactly as given in the base class. Feel free to gush prosaic in our subreddit at this nice solution to the problem of invoking distinct methods (with the same signature) on many objects sharing the same parent. Yippee! Problem solved! Your twelfth and final miniquest in this quest Yeah, I know an octopus only has 8 feet. But we're not mapping the miniguests to creature feet in our quests. Otherwise you'd never be able to complete my millipede quest. Implement: Stick_Man: :-Stick_Man () You must take care to explicitly delete every shape you created in your constructor before the Stick_Man destructor forgets the (presumably only) pointers to them in your code. When would that happen? Starter code Here are the (sometimes incomplete) class definitions you can use to flesh out your classes. I suggest you implement this quest in two files: A Shapes.h file which contains all the class definitions (skeleton below), and a Shapes.cpp file that contains implementations for all of the non-inline methods you declared in your classes. Before you decide to copy/paste the following code, remember that this is a PDF file. Some IDEs (esp. Xcode) are notoriously 12 of 16 bad at making certain control characters visible. So your code may fail to compile with no obvious syntax issues. I think your best bet is to read the code and type in your own version of it. Screen, friend of Shape 77 A virtual screen with pixels x: 0-1-1) and y: 0-ih-1) // NOTE: (0,01 is the bottom left - Pixels can be any character, determined 17 by each Point. class Screen friend class shape private size tu 13 std::vector> pix; public: static const char PG-BG.': Screen size_t w, size_t hi size_t get w const { return w; size t get h) const i return; } std::vector> get_pix() return pix; void set wisize_t n) W-W; } void set hisize_t n)-h; } void clear() { fill(BG);) void 2111 Ichar c); // TODO - Implement in the app File atd::string to string() const; friend std::stream operator 0 virtual -Point) 11 bool dram Screen 60, char ch - Screen::FG): 13 of 16 triand class Tests: // Don't renove // Line in two point notation class Line public Shape private: size t x1, yl, x2, y2; // Helpers static bool draw_by_x (Screen 53C1, char ch, size t x, size_t yl, size_t x2, size_t y2); static bool draw by y(screen scr, char ch. size_t xl, size_t yl, size_t x2, size_t y2); publici Line (size ta, size_t o, size t c, aizet ala), y(), 2(c), 724) II virtual Line) bool draw Screen CE, char ch Screen :: FG); friend class Tests // Don't remove 1: 77 Quadrilateral // A general quadrilateral with points x1, yl) ... 1**.4), clockwise 17 from bottom left. For the special case when xl x2, y2-y, 3-4 // and y4-yi, we'd use an upright Rectangle. // class Quadrilateral public Shape private: size_t x, yl, x2, y2, X3, 43, 44, 4, public: Quadrilateral size ta, size_t b, size te, size_t d, aizeta, size_t I, size_t 9, size_t n): _xltal. _Y11b), _x2(e), _Y210), _x3(e), _y3(E). _x445), _ych) {) virtual -Quadrilateral (1) baal drau Screen scr, char ch - Screen: :FG): friend class Tests; // Don't remove // --- Upright Rectangle, a special Quadrilateral 77 A Rectangle is a special upright Quadrilateral so we don't have to // paraneterize the constructor with a ton of numbers // class Upright_Rectangle : public Quadrilaterali public: Upright Rectangle(size_t xi, size tyl, size_t x2, size t y2) Quadrilateral(x1,xl, x1,2, *2.92, X2,1)) virtual -Upright_Rectangle (1) Stickman, a composite Shape class Stick Man publie shape static conat size_t DEFAULT M-20, DEFAULT 3-40; private: size_t X, Y, Whi atd::vector Shape -> parts 14 of 16 public: Stick_Manisize_t x - 0, size_t y = 0, size_t w - DEPAULT_W, size_t b - DEFAULT_H); virtual -Stick Man(); // Needed to deallocate parts const std::vector():>

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Recommended Textbook for

Mobile Communications

Authors: Jochen Schiller

2nd edition

978-0321123817, 321123816, 978-8131724262

Students also viewed these Programming questions

Question

How many moles of water are there in 1.000 L? How many molecules?

Answered: 1 week ago