Project 3: Train Station
Due: Thursday, March 31, 2016 by 9:00PM
Addenda
Updated TrainStation.cpp
A new version of TrainStation.cpp is available on GL and from the links on this web page (the old version is still available: TrainStation_old.cpp). The new version updates the destructor ~TrainStation() and the function removeTrain():
- ~TrainStation() now deletes all Train objects pointed to in the m_tracks array. As long as your Train destructor is correct, it will be called automatically before the program ends.
- removeTrain() deletes the Train object (if found in the m_tracks array) rather than just setting the pointer to NULL.
Adding and Removing Cars
The addCar() and removeCar() functions should maintain the correct order of the cars and the dependencies between cars, but they do not have guarantee the validity of the train (that it has one or more locomotives and at least one coach car — this is done by the isValid() function).
- If I add or remove a CoachClass car, I need to check if there is a SnackCar, and, if so, determine if it needs to be moved.
-
If the train has a SnackCar and the user requests to add another,
the addCar() function should do nothing
and return ‘false’. - A train has a DiningCar if and only if it has at least one SleepingCar. There can be at most one DiningCar. The preferred way to remove a DiningCar is to remove all SleepingCars — you should automatically remove the DingCar when the last SleepingCar is removed. In this case, if a user requests to remove the DiningCar directly, removeCar() should do nothing and return ‘false’. If you choose to allow the user to remove the DiningCar directly, you must also remove all sleeping cars.
-
Similarly, the preferred way to add a DiningCar is to add one or
more SleepingCars — you should automatically add the DiningCar
when the first SleepingCar is added. In this case, if a user
requests to add the DiningCar directly, addCar() should
do nothing
and return ‘false’. If you choose to allow the user to add the DiningCar directly, you must also add a SleepingCar. - It should be possible to create an ‘invalid’ train, one that lacks either a locomotive or coach class cars; this will be caught by the isValid() function.
Warning from Train() and TrainCar() Constructors
When compiling with -Wall you will receive a warning about the order of intialization of class variables in Train and TrainCar. You may ignore these warnings, or you may change the order of the items in the initialization list to remove the warnings.
Valgrind
Since this project makes extensive use of dynamic memory, it is important that you test your program for memory leaks using valgrind:
valgrind mytest
If you have no memory leaks, you should see output like the following:
==14746== ==14746== HEAP SUMMARY: ==14746== in use at exit: 0 bytes in 0 blocks ==14746== total heap usage: 42 allocs, 42 frees, 931 bytes allocated ==14746== ==14746== All heap blocks were freed -- no leaks are possible ==14746== ==14746== For counts of detected and suppressed errors, rerun with: -v ==14746== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6)
The important part is “in use at exit: 0 bytes 0 blocks,” which tells me all the dynamic memory was deleted before the program exited. If you see anything other than "0 bytes 0 blocks" there is probably an error in one of your destructors.
Objectives
The objectives of this project are:
- To implement a linked-list data structure,
- To practice using C++ class syntax,
- To practice implementing member functions,
- To practice implementing overloaded operators, and
- To practice object-oriented thinking.
Background
Linked lists are a fundamental and widely-used data structure. In this project, you will implement a linked list to store the cars of a train in their proper order. As cars are added to the train, your implementation must ensure that they are inserted at the correct position within the list; similarly, when a car is removed from a train, you must check that the remaining cars are still in their proper position, and re-position them if necessary.
For our purposes, a train consists of six different types of cars: locomotives, coach cars, business class cars, sleeping cars, snack cars, and dining cars; a train must have at least one locomotive and one coach car, but the other car types are optional. The car types, along with a value NoType, are defined as an enumeration in the file TrainCar.h:
typedef enum { Locomotive, CoachClass, BusinessClass, DiningCar, SnackCar, SleepingCar, NoType } cType;
There are a number of rules regarding the location of each type of car within the train. The locomotives and passenger cars must be in this order:
- Locomotive(s)
There may be one or more locomotives. They must be the first non-dummy nodes of the linked list.
- BusinessClass
BusinessClass cars are optional, but if they are present, must be the first cars after the locomotives.
- CoachClass
Every train must have at least one CoachClass car. If there are no business class cars, then they are immediately after the locomotives; otherwise, they follow the business class cars, possibly separated by a SnackCar (see below).
- SleepingCar
SleepingCars, like business class cars, are optional. They are always the last cars in the train, following the coach cars and dining car.
- SnackCar
A SnackCar is optional; there can be at most one.
If the train has both business class and coach class, the SnackCar must be placed between coach and business.
If the train has no business class, then the SnackCar must be placed in the middle of the coach class cars; if there is an odd number of coach class cars, it should be placed closer to the locomotives.
- DiningCar
A train has a DiningCar if and only if it has one or more sleeping cars. The DiningCar should be placed between the coach cars and the sleeping cars.
The TrainCar class is defined in TrainCar.h and implemented in TrainCar.cpp. It is equivalent to the Node class in other linked-list examples you have seen: it has one data field (the car type) and a pointer to the next TrainCar object. The TrainCar class is nearly complete, but you do need to implement the overloaded operator<< to complete it.
The "meat" of the linked list is in the Train class defined in Train.h and implemented in Train.cpp. The Train class stores basic information a bout a train, including it's number, destination, and departure time and also has a pointer to the first (dummy) node of the linked list. It implements all the functions necessary to insert and remove cars in a Train and has an overloaded operator<< that prints a character graphic representation of the train. You are given implementations of two Train constructors, but you must implement the remainder of the class.
Finally, there is a small Time class that you must implement from scratch (no files are provided). The Time class is used to represent train departure times, to do simple arithmetic with times, and to output times in a nice format.
Assignment
Your assignment is to complete the implementations of the TrainCar and Train classes and to write a Time class from scratch.
The TrainCar class is defined in TrainCar.h and implemented in TrainCar.cpp. You only need to implement the overloaded insertion operator to complete the class.
The Train class is defined
in Train.h and implemented
in Train.cpp. Only the constructors
are provided; you must implement the remaining functions. Do not
forget to implement the
destructor ~Train() ~TrainCar().
The Time class must be written "from scratch." The class is used to store, compare, and output times on a 24-hour clock. The interface must be in Time.h, the implementation must be in Time.cpp, and the class must have the following features:
- Two integer variables: one to store hours, the other to store minutes.
- Default constructor sets hours and minutes to 0.
- Non-default constructor sets hours and minutes to specified values; must check that specified values are valid.
- Overloaded operator<< must print times with a colon between hours and minutes and with zero-padding of single-digit hours or minutes.
-
Overloaded operator+ to add minutes to a time object. For example,
Time t(13, 55); cout << t + 7 << endl;
should print "14:02". -
Overloaded operator< to compare two Time objects. For example,
Time t0(13, 55); Time t1(14, 00); bool b = (t0 < t1); // b gets value true bool c = ((t0 + 7) < t1); // c gets value false
Your classes must work with the provided TrainStation class:
This class creates several "tracks," assigns trains to the tracks, prints scheduled departures, etc. In addition, one test file is provided, station_test.cpp, which exercises all the class in the projects (TrainStation, Train, TrainCar, and Time). As with previous projects, you should do lots of additional testing — station_test.cpp is just one example of a test program.Implementation Issues
Here are some issues to consider and pitfalls to avoid:
- Reminder: do not develop your programs in the submission directories. Develop your programs in some other location in GL or on your own computer. The files that you have in the submission directory should not be your only copy of your code.
- Practice incremental development. This means you should write a small piece of code, then test it and debug it. You should finish the testing and debugging before you write more code.
- There is no reason to change the class definition of TrainCar, thus you should make no changes to the TrainCar.h file. On the other hand, you are permitted to private helper functions to the Train class. You may add declarations of private helper functions near the end of Train.h. Do not otherwise change the header file for the Train class.
- On GL, you can compile the test program with your
implementation with one command, as follows:
linux3% g++ -Wall -ansi -gstabs station_test.cpp TrainStation.cpp Train.cpp TrainCar.cpp Time.cpp
or separately, like this:linux3% g++ -Wall -ansi -gstabs -c station_test.cpp linux3% g++ -Wall -ansi -gstabs -c TrainStation.cpp linux3% g++ -Wall -ansi -gstabs -c Train.cpp linux3% g++ -Wall -ansi -gstabs -c TrainCar.cpp linux3% g++ -Wall -ansi -gstabs -c Time.cpp linux3% g++ -gstabs station_test.o TrainStation.o Train.o TrainCar.o Time.o
You only need to recompile a .cpp file if you change it. - Sample output from station_test.cpp is available: station_test-output.txt. Your program does not have to produce output that is identical to the sample output (but it still has to be correct).
-
The source files linked on this web page are also available in the following directory on GL.
/afs/umbc.edu/users/c/m/cmarron/pub/cmsc202/proj3/
This is a directory, not a command. Use the Unix cp command to copy files.
Submitting your program
You should submit these files to the proj3 subdirectory:- Train.cpp This should contain your implementations of all of the Train member functions. This file should not have a main() function.
- Train.h You may not have made any changes to this file, but you are permitted to add private helper functions.
- TrainCar.cpp This file contains the completed TrainCar class; you only needed to complete the overloaded operator<<. This file should not have a main() function.
- Time.h This file should contain the inerface for your Time class.
- Time.cpp This file should contain the implementation of your Time class. This file should not have a main() function.
- mytest.cpp This file should have a main() function that exercises the working parts of your submission, using the Train and TrainStation classes. This is where you tell us what works. If you could not get some member function to work, don't test it here. We will test all functions with other programs.
You do not need to submit TrainCar.h, TrainStation.h, TrainStation.cpp, or station_test.cpp because these files should not have changed.
If you followed the directions in setting up shared directories, then you can copy your code to the submission directory with:
cp Train.h Train.cpp TrainCar.cpp Time.h Time.cpp mytest.cpp ~/cs202proj/proj3/
You can check that your program compiles and runs in the proj3 directory, but please clean up any .o and executable files. Again, do not develop your code in this directory, and do not keep the only copy of your program here.
If you are submitting late, you need to copy to proj3-late1, or proj3-late2 instead of proj3. Make sure you understand the course late submission policy.