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
Point
class inpoint.h
andpoint.cpp
-
Define a
HorizontalLine
class inhorizontalLine.h
andhorizontalLine.cpp
-
Define a
VerticalLine
class inverticalLine.h
andverticalLine.cpp
-
Define a
Rectangle
class inrectangle.h
andrectangle.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
int
parameters for x position and y position -
one
char
parameter for display symbol
It must contain the following private member variables:
-
int
variablesx
andy
-
char
variablesymbol
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
int
parameters for x position, y position, and length -
one
char
parameter for display symbol
They must contain the following private member variables:
-
int
variablesx
,y
, andlength
-
char
variablesymbol
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
HorizontalLine
with x position 2, y position 5, length 3, and display symbol '$'; and -
a
VerticalLine
with 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
int
parameters for x position, y position, width, and height -
one
char
parameter for display symbol
It must contain the following private member variables:
-
int
variablesx
,y
,width
, andheight
-
char
variablesymbol
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
Picture
constructor. The constructor must prepare thePicture
to be used, so you will need to initialize thenumberOfShapes
andshapes
variables. YourPicture
starts 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 theshapes
variable to an array of size50
. -
Implement a
Picture
destructor (named~Picture
). The destructor must clean up everything in the picture. Since shapes added to a picture will be owned by that picture, the~Picture
destructor is responsible for deleting them. -
Implement an
addShape
method. 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
toString
method. This method should create a grid, draw all of theShape
s 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
main
function of the filemanualTests.cpp
. Then, you can runmake manualTests
and./manualTests
. This gives you a playground in which you can experiment with the classes and objects you are writing. You can runvalgrind
onmanualTests
to 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
Picture
and at least oneShape
, you can runmake
and./artwork
. This will allow you to draw shapes onto a picture. You can use this even if you haven’t written all of theShape
subclasses; it just won’t work for the shapes you haven’t finished yet. -
You can run
make tests
followed by./tests
to 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 finishedPoint
but 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
, andwhile
conditions 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
Picture
class that contains manyShape
s and draws them all onto aGrid
. -
You should be able to run
make tests
and./tests
on 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!