Lab 3: Shapes
Due on Wednesday, September 25th at 11:59pm. This is an individual lab. You are to complete this lab on your own, although you may discuss the lab concepts with your classmates. Remember the Academic Integrity Policy: do not show your code to anyone outside of the course staff and do not look at anyone else’s code for this lab. If you need help, please post on the Courselore forum or reach out to the course staff. If you have any doubts about what is okay and what is not, it’s much safer to ask than to risk violating the Academic Integrity Policy.
Overview
In this lab, you will design a hierarchy of classes. You will become familiar with the following in C++:
-
Classes and Objects
-
Inheritance
-
Polymorphism
-
Memory management
As with the previous labs, you should clone your repository. The URL is:
git@github.swarthmore.edu:cs35-f24/lab03-<your-username>
We will describe this lab in three parts, the last of which has been provided for you. You are strongly encouraged to read this entire lab write-up when you begin this assignment! Later in the write-up, we give suggestions on how to get started.
Part 1: Creating Shape Classes
The first part of this lab involves defining classes that represent different kinds of shapes. Each of our shapes may look different, but they all have something in common: we can draw them onto a grid.
By default the grid will be 20 wide and 10 high. You may assume that the user always provides valid coordinates that lie within the grid’s boundaries.
Hierarchy of Classes
A Shape class is provided for you in shape.h. This is a purely virtual class and therefore we do not need a shape.cpp file.
You need to do the following:
-
Define a
Pointclass inpoint.handpoint.cpp -
Define a
HorizontalLineclass inhorizontalLine.handhorizontalLine.cpp -
Define a
VerticalLineclass inverticalLine.handverticalLine.cpp -
Define a
Rectangleclass inrectangle.handrectangle.cpp
Class declarations go in the header files (.h) while class implementations go in the source files (.cpp).
The following sections describe specifications for the Rectangle, HorizontalLine, VerticalLine, and Point classes. You must abide by these specifications.
Point Class
Your Point class is a subclass of Shape. It must contain a constructor that takes as input (order matters):
-
two
intparameters for x position and y position -
one
charparameter for display symbol
It must contain the following private member variables:
-
intvariablesxandy -
charvariablesymbol
Because the Point class is a subclass of Shape, it must contain a public method called draw with one input argument of type Grid* and return type void. The draw method places the display symbol onto the grid at the appropriate location.
For example, consider a Point with x position 5, y position 6, and display symbol 'O'. We create this point using the following code:
Shape* myShape = new Point(5, 6, 'O');
When drawn on the grid, the point will appear as follows. Recall that the upper left corner of the grid has coordinate (0,0), just as in the PicFilter lab.
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * O * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
HorizontalLine and VerticalLine Classes
Your HorizontalLine and VerticalLine classes are also subclasses of Shape. They must contain constructors that take as input (order matters):
-
three
intparameters for x position, y position, and length -
one
charparameter for display symbol
They must contain the following private member variables:
-
intvariablesx,y, andlength -
charvariablesymbol
As with Point, the HorizontalLine and VerticalLine classes must implement the draw method. A HorizontalLine object starts at the given x and y coordinates and extends to the right occupying cells on the grid. The number of cells that the HorizontalLine occupies is equal to its length. A VerticalLine object is the same but extends down occupying cells.
For example, let us consider a grid with two shapes:
-
a
HorizontalLinewith x position 2, y position 5, length 3, and display symbol '$'; and -
a
VerticalLinewith x position 5, y position 0, length 4, and display symbol '@'
We create these shapes using the following code:
Shape* myShape1 = new HorizontalLine(2, 5, 3, '$'); Shape* myShape2 = new VerticalLine(5, 0, 4, '@');
The lines would appear on the grid as follows:
* * * * * @ * * * * * * * * * * * * * *
* * * * * @ * * * * * * * * * * * * * *
* * * * * @ * * * * * * * * * * * * * *
* * * * * @ * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * $ $ $ * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
Rectangle Class
Your Rectangle class is also a subclass of Shape. It must contain a constructor that takes as input (order matters):
-
four
intparameters for x position, y position, width, and height -
one
charparameter for display symbol
It must contain the following private member variables:
-
intvariablesx,y,width, andheight -
charvariablesymbol
As a Rectangle is also a subclass of Shape, it too must implement the draw method correctly. We will draw solid rectangles that are filled-in with the rectangle’s symbol.
For example, consider a Rectangle with x position 3, y position 0, width 5, height 3, and display symbol 'X'.
We create this rectangle using the following code:
Shape* myShape = new Rectangle(3, 0, 5, 3, 'X');
The rectangle would appear on the grid as follows:
* * * X X X X X * * * * * * * * * * * *
* * * X X X X X * * * * * * * * * * * *
* * * X X X X X * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
Part 2: The Picture Class
With an idea of what shapes are, we can define the idea of a "picture": a set of shapes drawn in specified order. The shapes in a picture have a specified order because we may draw shapes on top of other shapes.
Class Structure
The design for the Picture class is provided for you in picture.h. It’s your job to fill in the implementation for the Picture class in picture.cpp.
The Picture class contains the following private member variables:
-
int numberOfShapes -
Shape** shapes
The numberOfShapes variable keeps track of how many shapes have been added to the picture. The shapes variable keeps track of those shapes.
The shapes variable has the type Shape**, which is new to our labs. Just as an int* variable can be used to point to an array of int values, a Shape** variable can be used to point to an array of Shape* values. That is, the Shape** type of the shapes variable can be read as "a pointer to an array of pointers to Shape objects". Because the array does not require a specific type of Shape, the pointers may point to a mixed collection of shapes: Point, HorizontalLine, VerticalLine, and Rectangle objects.
Your Tasks
To complete the Picture class, you will need to complete the following tasks.
-
Implement a
Pictureconstructor. The constructor must prepare thePictureto be used, so you will need to initialize thenumberOfShapesandshapesvariables. YourPicturestarts with no shapes in it but must be ready to add shapes in the future. You may assume that users will never add more than fifty shapes to a picture, so you may initialize theshapesvariable to an array of size50. -
Implement a
Picturedestructor (named~Picture). The destructor must clean up everything in the picture. Since shapes added to a picture will be owned by that picture, the~Picturedestructor is responsible for deleting them. -
Implement an
addShapemethod. This method takes aShape*that points to a shape and adds it to the picture. (You’ll need to keep it in your array so you can draw it later.) -
Implement a
toStringmethod. This method should create a grid, draw all of theShapes onto it, and then convert the grid to a string that you return. (Remember: if you dynamically allocate any objects during this process, you’ll need to clean them up!)
Part 3: The Artwork Program
The third part of this assignment is a program called artwork that allows the user to draw a picture using the classes you have defined. Don’t worry: the artwork program has been written for you! Once you have defined a Shape class and a Picture class, you can run make followed by ./artwork and experiment with the classes you have built.
Getting Started
When you first clone your Git repository for this assignment, it will contain the following starter files. Those that are highlighted require modification.
-
Makefile- instructions for compiling your program. -
shape.h- design for virtual Shape class -
rectangle.h,rectangle.cpp- design & implementation for Rectangle class -
horizontalLine.h,horizontalLine.cpp- design & implementation for HorizontalLine class -
verticalLine.h,verticalLine.cpp- design & implementation for VerticalLine class -
point.h,point.cpp- design & implementation for Point class -
picture.h,picture.cpp- design & implementation for Picture class -
grid.h,grid.cpp- design & implementation for Grid class -
artwork.cpp- main methods for running application that creates shapes -
shapeFactory.h,shapeFactory.cpp- behind-the-scenes code for creating shapes -
tests.cpp,manualTests.cpp- programs that can test your code
Note: A generally good strategy for tackling this lab is to start by implementing Point (the Shape with the shortest draw method), then to implement Picture (so you can start testing with the artwork program), and then to implement the remaining shapes.
Testing Your Code
There are at least three ways to test your code in this lab:
-
You can write code in the
mainfunction of the filemanualTests.cpp. Then, you can runmake manualTestsand./manualTests. This gives you a playground in which you can experiment with the classes and objects you are writing. You can runvalgrindonmanualTeststo track down bugs in your classes. See below for an example of how to draw multiple shapes onto a picture and print them. -
Once you have implemented
Pictureand at least oneShape, you can runmakeand./artwork. This will allow you to draw shapes onto a picture. You can use this even if you haven’t written all of theShapesubclasses; it just won’t work for the shapes you haven’t finished yet. -
You can run
make testsfollowed by./teststo run some automated tests. You can run these tests before you’re finished with the lab; even though many tests will fail, the names of those tests should indicate whether the failure is because you have not yet finished the lab or because something is wrong with what you have written. For instance, if you have finishedPointbut notRectangle, you can ignore failing tests with "rectangle" in their names, but failing tests with "point" in their names might indicate that you need to fix your code before moving on.
An Example for Drawing Multiple Shapes
The following creates three rectangles:
Shape* myShape1 = new Rectangle(0, 0, 7, 7, '$'); Shape* myShape2 = new Rectangle(1, 1, 6, 4, '-'); Shape* myShape3 = new Rectangle(3, 2, 4, 3, 'z');
The following adds the three shapes to a picture:
Picture myPicture; myPicture.addShape(myShape1); myPicture.addShape(myShape2); myPicture.addShape(myShape3);
The following will draw the shapes one after another onto a Grid and print the result to the command line:
myPicture.print();
The result looks as follows:
$ $ $ $ $ $ $ * * * * * * * * * * * * *
$ - - - - - - * * * * * * * * * * * * *
$ - - z z z z * * * * * * * * * * * * *
$ - - z z z z * * * * * * * * * * * * *
$ - - z z z z * * * * * * * * * * * * *
$ $ $ $ $ $ $ * * * * * * * * * * * * *
$ $ $ $ $ $ $ * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
Coding Style Requirements
You will also be required to observe good coding practices:
-
Your C++ code must have proper and consistent indentations.
-
You must have proper and consistent usage of spacing and braces for
if,else,for, andwhileconditions as well as class definitions and code blocks. -
Always comment any declarations you introduce to .h files or elsewhere.
Summary
To summarize the requirements of this lab:
-
You must declare and define four subclasses of
Shape:Point,HorizontalLine,VerticalLine, andRectangle. -
You must define a
Pictureclass that contains manyShapes and draws them all onto aGrid. -
You should be able to run
make testsand./testson the lab machines without any errors. -
Your program should not have any memory leaks or errors.
Questionnaire
Once you have submitted your lab, please make sure to complete its corresponding questionnaire. The questionnaire will typically take less than a minute and helps us to understand how much work the labs are so we can adjust appropriately. Completing the questionnaire is part of your participation grade, so don’t forget to fill it out!