COSC-052: Computer Science II

Project 2
Spring 2013

Due: Mon, Feb 25 @ 5 PM
6 points

In this project, you will use classes, inheritance, and polymorphism to implement software that stores information about different types of bikes. For simplicity, we will assume that bikes are one of two types: delivery or urban.

I have drawn a class diagram for the project using the Unified Modeling Language (UML), which appears in the image below. Computer scientists and software engineers commonly use UML to design software and to communicate those designs. We will discuss the diagram in class, but its interpretation should be relatively straightforward.

A rectangle represents a class and is divided into three sections for the class's name, its data members (or attributes or properties), and its methods (or operators). Characters precede attributes and methods. The hyphen (-) denotes private, the pound sign (#) denotes protected, and the plus sign (+) denotes public.

As the diagram indicates, you should implement the Bike class and use inheritance to derive two subclasses, Delivery and Urban. All bikes have an ID, a name, and a number of gears, which must be protected. Delivery bikes have a carrying capacity. Each class should have virtual methods that read and print the bike's information from and to a stream. Naturally, the set methods should perform range checks and throw invalid_argument when values are out of range.

Storing information about a single bike is not very interesting, so also implement a Bikes (plural) class that stores pointers to Bike objects in a C++ vector. As the composition link in the diagram indicates, there is a one-to-many relationship between the Bikes class and the Bike class. The UML diagram depicts the vector as a private attribute of the Bikes class, but you could also derive Bikes from the vector class. Implement methods to read bikes from a file, print the bikes stored in the vector, compute the total number of gears of all of the bikes, and compute the total carrying capacity of the delivery bikes.

The file format consists of a bike's ID, name, number of gears, and if it is a delivery bike, its carrying capacity. The ID is a three-character string. The first character is either 'U' or 'D' to indicate whether the ID corresponds to an urban bike or a delivery bike. The next two characters are digits and represent an inventory code. The name is delimited with double quotes. The number of gears and the carrying capacity are integers. An example of bikes in this format is as follows:

U01 "Trek Soho Deluxe" 8
D01 "Trek Transport+" 8 80
D02 "Johnny Loco Cargo Cruiser" 8 75
U02 "Johnny Loco Urban Londoner" 3
U03 "Johnny Loco Urban Moscow" 1
U04 "Kona Dew DL" 9
D03 "Kona Minute" 8 70
D04 "Kona Ute" 8 100

As Bikes::read reads the input file, it uses BikeFactory::make to make either a Delivery object or an Urban object a based on the contents of the input stream. Once BikeFactory::make determines whether the information in the stream corresponds to a delivery bike or an urban bike and creates the appropriate object, it invokes the polymorphic read method to fully instantiate the object. The factory can determine which subtype of Bike to make by examining the first character of the ID. It should then use iostream::putback to put the character back into the input stream so the object's read method can process the information in the stream properly.

A Factory is a common method pattern in object-oriented programming. As the name suggests, it is a class designed to produce objects. For this project, its method make returns a pointer to either an Urban object or a Delivery object.

In the main function, write a simple driver program that constructs a Bikes object, reads bikes from the file bikes.dta, prints them to the console, prints the total number of gears of those bikes, and prints the total carrying capacity of the delivery bikes. If the data file does not exist, then main should issue an appropriate message and exit. It should also catch any thrown exceptions.

Use stepwise refinement and incremental development. For example, implement the Bike class and test it thoroughly before implementing, say, the Delivery class.

All class definitions and class methods of the Bike class must be documented with documentation comments. Doc comments for class definitions must include @author and @version tags. Doc comments for methods must include @param, @return, and @throw tags, where appropriate. In an optional homework, you'll learn how to generate documentation from these comments and post them to the Web.

Getting Started

I'm sure that writing your own Makefile for p1 was fun, but for p2, you'll use a Makefile that is less obvious, but more general. You should be able to use it for the rest of the projects this semester.

To get started, log on to cs-class, create a directory, and copy over my Makefile:

cs-class% mkdir p2
cs-class% cd p2
cs-class% cp ~maloofm/cosc052/Makefile.p2 ./Makefile
cs-class% ls
Makefile
cs-class%
I'll explain this Makefile in class. It might be a useful exercise to get this Makefile working for your solution to p1 just to make sure you know what you're doing.

Instructions for Electronic Submission

At the top of the file main.cc (or the file containing the main function), place the following header comment, with the appropriate substitutions:

/*
 * COSC 052 Project 2
 * Name: <your name>
 * ID: <GoCard ID>
 * E-mail: <e-mail address>
 * Instructor: Maloof
 *
 * In accordance with the class policies and Georgetown's Honor Code,
 * I certify that, with the exceptions of the class resources and those
 * items noted below, I have neither given nor received any assistance
 * on this project.
 */

You'll be submitting p2 exactly like you submitted p1. If you need to include a message about your submission, then place the message in a file named README. Place the README file in the project's directory.

Copyright © 2019 Mark Maloof. All Rights Reserved. This material may not be published, broadcast, rewritten, or redistributed.