
In Lab 4 you built a Time class. In this lab you will use it: a movie theater needs to schedule showings,
and a showing is a movie together with the time it starts.
Three new ideas, in order:
TimeSlot will containTime.You will need your finished time.cpp from Lab 4. Start by copying it into a new directory.
Some values come from a short, fixed list. A movie’s genre is one of a handful of possibilities, and nothing
else is meaningful. You could store the genre as an int and remember that 0 means action and 1 means
comedy — but then nothing stops you writing genre = 47, and every reader of your code has to remember the
numbering.
An enumerated type lets you name the possibilities instead:
enum Genre { ACTION, COMEDY, DRAMA, ROMANCE, THRILLER };
That single line creates a new type called Genre, and five named values of that type. Now you can write:
Genre myFavorite = COMEDY;
The names are called enumerators, and by convention they are written in all capitals. Behind the scenes
each one has an integer value — ACTION is 0, COMEDY is 1, and so on — but the type system keeps them
apart from ordinary integers. myFavorite = 3; will not compile, which is the point: the only values a
Genre can hold are the five you named.
When you genuinely need the number, ask for it explicitly with a cast:
static_cast<int>(COMEDY) // 1
cout << myFavorite; prints 1, not COMEDY — the names exist for the compiler’s benefit, not the
terminal’s. To print the name, you have to write the translation yourself, and a switch is the natural
shape for it:
switch (mv.genre)
{
case ACTION : g = "ACTION"; break;
case COMEDY : g = "COMEDY"; break;
case DRAMA : g = "DRAMA"; break;
case ROMANCE : g = "ROMANCE"; break;
case THRILLER : g = "THRILLER"; break;
}
Looking ahead. C++11 added a stricter form written
enum class Genre { ACTION, ... }, where the
enumerators must be qualified asGenre::ACTIONand no implicit conversion tointhappens at all. It is
the form used throughout Chapter 11, so you will meet it again. This lab uses the plainenumabove.
Movie classCreate a program theater.cpp. Copy in your Time class from Lab 4, and add the Genre enumerated type
above it.
Now write a class Movie with three private member variables:
string title;
Genre genre;
int duration; // in minutes
and a public interface consisting of two constructors — a default one and one taking all three values — plus
accessors for each member. Give duration a mutator that rejects negative values, the way you did with
Time’s hours and minutes.
Also write a free function
string genreName(Genre g);
that returns the printable name of a genre, using the switch above. It is a free function rather than a
member of Movie because it is about Genre, not about any particular movie.
Test it in main by creating two movies and printing their details:
Back to the Future (COMEDY, 116 min)
Black Panther (ACTION, 134 min)
TimeSlot: a class containing another classA time slot is a movie together with the time it starts. Write a class TimeSlot whose private member
variables are:
Movie movie; // what is showing
Time startTime; // when it starts
This is composition: a TimeSlot object contains a Movie object and a Time object inside it. The
relationship is called has-a — a time slot has a start time — and it is one of the two ways classes get
built out of other classes.
That last point is the one worth pausing on. Containing a Time does not give TimeSlot any special
privileges over it. Inside a TimeSlot member function, startTime.hour is still a compiler error —
TimeSlot must go through Time’s public interface exactly like anyone else. Your Time class does not
have to be modified in any way to be used here, which is precisely the payoff of having written it properly.
Give TimeSlot a constructor taking a Movie and a Time, accessors for both, and:
Time endingTime() const;
which returns the time the showing ends — the start time plus the movie’s duration. If Lab 4’s addMinutes
works, this is one line.
Then write a free function void printTimeSlot(const TimeSlot &ts); producing:
Black Panther (ACTION, 134 min) [starts at 16:45, ends by 18:59]
Write a main that defines at least five time slots — a morning, daytime, and evening showing, plus a couple
of your own favorite movies (durations are on IMDB) — and prints them all. Make sure your slots end before
midnight, since addMinutes was not required to handle rolling over into the next day.
Add two more member functions to TimeSlot.
TimeSlot scheduleAfter(const Movie &nextMovie) const;
returns a new TimeSlot for nextMovie, starting exactly when this one ends. If a slot starts at 14:10
and its movie runs 120 minutes, the next slot starts at 16:10.
bool overlaps(const TimeSlot &other) const;
returns true if the two showings overlap in time, taking both start times and both durations into account.
Hint: convert both start times to minutes since midnight. Two showings overlap when one starts before the
other ends. Be careful at the boundary: a movie ending at exactly 11:30 does not overlap one starting at
11:30, but it does overlap one starting at 11:29.
Test overlaps on pairs you have worked out by hand, including one pair that touches exactly at the boundary
in each direction.
Your theater.cpp now holds three classes, several free functions, and a main. That is enough that finding
anything in it has become annoying — and if another program wanted to use your Time class, the only way to
share it would be to copy and paste.
The standard solution is to give each class two files of its own, and to keep the program that uses them
in a third:
Time.h — the specification file. It contains only the class declaration: the member variables andTime includes this file.Time.cpp — the implementation file. It contains the definitions of the member functions.main.cpp — the client program. The code with main that creates and uses objects.Here is what Time.h looks like:
// Time.h is the Time class specification file.
#ifndef TIME_H
#define TIME_H
class Time
{
private:
int hour;
int minute;
public:
Time();
Time(int h, int m);
bool setHour(int h);
bool setMinute(int m);
int getHour() const;
int getMinute() const;
int minutesSinceMidnight() const;
int minutesUntil(const Time &later) const;
Time addMinutes(int mins) const;
};
#endif
Only the declaration — no function bodies, no main.
Those three preprocessor lines are an include guard, and they solve a real problem. If main.cpp includes
both Time.h and TimeSlot.h, and TimeSlot.h also includes Time.h, then the compiler would see the
Time class declared twice and refuse to continue. #ifndef TIME_H means “if not defined”: the first time
the file is included, TIME_H gets defined and the rest of the file is processed. Every later #include of
the same file finds TIME_H already defined and skips straight to #endif.
The convention for the name is the file name in capitals with the dot replaced by an underscore: TIME_H,
MOVIE_H, TIMESLOT_H.
// Time.cpp is the Time class implementation file.
#include "Time.h"
Time::Time()
{
hour = 0;
minute = 0;
}
int Time::minutesSinceMidnight() const
{
return hour * 60 + minute;
}
Note the double quotes in #include "Time.h". Quotes tell the compiler to look in the current project
directory; angle brackets, as in #include <iostream>, tell it to look where the system headers live. Use
quotes for your own files and brackets for the library’s.
Note also what Time.cpp does not include: <iostream>. The class does no input or output of its own —
that is the client program’s job, and it is why printTimeSlot is a free function rather than a member. A
class that insists on printing to the screen cannot be reused by a program that has no screen.
g++ needs to be given every .cpp file. The headers are not listed — they are pulled in by the #include
lines:
$ g++ main.cpp Time.cpp Movie.cpp TimeSlot.cpp -o schedule
$ ./schedule
If you get an error that says undefined reference to Time::addMinutes(int), you have almost certainly
left a .cpp file off that command line. The compiler found the declaration in the header and believed you;
the linker then went looking for the actual function and could not find it.
Break theater.cpp into eight files:
Time.h Time.cpp
Movie.h Movie.cpp
TimeSlot.h TimeSlot.cpp
main.cpp
(That is seven — the eighth is the Makefile you will wish you had by the end of the semester.)
Some things to work out as you go:
TimeSlot.h needs the declarations of Movie and Time, because it has members of those types. IncludegenreName and printTimeSlot are free functions, not members. Decide where they belong and be able toGenre enum go? It is needed by Movie.h and by anything that calls genreName.Confirm that the program still produces exactly the output it did before the split. Nothing about its behavior
should have changed — only its arrangement.
The classes in this lab were handed to you. Finding them yourself is the harder half of the job, and there is
a method for it: write down the nouns.
Here is a problem domain:
A community pool tracks its swim lessons. Each lesson has an instructor, a skill level, a day of the week,
and a start time, and runs for a fixed number of minutes. A swimmer signs up for lessons; the pool records
the swimmer’s name, phone number, and which lessons they are enrolled in. No lesson may be scheduled at the
same time as another lesson taught by the same instructor.
On paper, not in code:
Then answer one question in a comment: your TimeSlot class and the Time class already solve part of this
problem. Which part, and what would you have to add?
Submit all seven source files from Task D. Do not submit the compiled executable or any .o files.
Each file should start with a comment that contains your name and a short description, for example:
/*
Author: your name
Course: CSCI-135
Instructor: their name
Assignment: Lab5
Here, briefly, at least in one or a few sentences
describe what this file contains.
*/