Overview

In this assignment you will be creating a command line menu driven application that implements a simple phone book.

The classes menuList and menuItem implement a simple menu system. One instance of menuItem is created for every menu command you need in your application. Each menuItem contains the char needed to select an item, the text for the menu item, and an instance of a subclass of the abstract class command. The command actually performs the action specified by the selected menuItem instance. Each of the menuItem instances is added to an instance of the menuList class.

The classes menuList, menuItem and the abstract class command have been provided for you. The menuItem, and menuList classes are declared and implemented in files menuList.h and menuList.cpp. The abstract class command is defined in file command.h.

You can inline some of your functions, but you cannot inline all of them. If you want to inline functions only inline short functions with 5 or 6, or fewer, lines of code.

The following files are can be downloaded from zyBooks:

menuList.h
menuList.cpp
command.h

The following files are on eLearning in the "Sample Programs" area in entry "Additional Files to test the menu classes used for Assignment 2".

testmenu.cpp
incrementCommand.h
decrementCommand.h

The files menuList.h, menuList.cpp, and command.h will be needed for your application. The other files are there to help you learn how the classes work.

The testmenu.cpp file is a simple program that implements a menu that allows you to increment and decrement an int value.

The incrementCommand.h and decrementCommand.h file implement the increment and decrement commands. Run this program in your IDE to get familiar with the command, menuList, and menuItem classes.

Note that the menu classes are independent of what actual work they are performing. All of the work is encapsulated in the subclasses of the command class. This way we can use the menuList and menuItem classes with a wide variety of menu applications.

You will be using these classes to implement your simple phone book application.

Classes you will need to write

You will be writing the following classes (and associated .h and .cpp files).

Class name Header file name Source file name Description
phoneBookEntry phoneBookEntry.h phoneBookEntry.c This class will represent an entry in the phone book. It contains the name, phone number and e-mail address
phoneBook phoneBook.h phoneBook.cpp This is the phoneBook and contains phoneBookEntry values. You can add, update, and remove entries from the phoneBook and you can print the contents of the phoneBook
bookCommand bookCommand.h bookCommand.cpp This is a subclass of the command class. It will implement some helper functions needed by the add/update, and erase commands
printCommand printCommand.h printCommand.cpp Command that prints the phoneBook when the command is executed by the menu
addUpdateCommand addUpdateCommand.h addUpdateCommand.cpp This command will add a new entry if the passed in name is not already in the phoneBook. Otherwise it will update and existing phoneBookEntry
eraseCommand eraseCommand.h eraseCommand.cpp Removes the specified phoneBookEntry (if it exists)

NOTE: You must NOT use the using namespace std; statement in any of your .h files. You will have to qualify built-in classes like string and vector as std::string and std::vector. You must not use any using statement in the header files.

NOTE: You must have the above classes and .h and .cpp files. They must have the names specified. Failure to do this could result in unit tests failing.

phoneBook and phoneBookEntry classes

You are going to be creating a phone book using std::vector class. The entries being added are going to be of type phoneBookEntry.

The phoneBookEntry class will contain three std::string values for name, phone number, and e-mail address.

Here are the requirements for the phoneBookEntry class.

You will need four constructors for the phoneBookEntry class as follows:

phoneBookEntry();
phoneBookEntry(const std::string &name, const std::string &number);
phoneBookEntry(const std::string &name, const std::string &number, const std::string &email);
phoneBookEntry(const phoneBookEntry &from);
const phoneBookEntry& operator=(const phoneBookEntry &from);

NOTE: that the last two above are the copy constructor and the assignmente operator.

In addition you will need the following accessors. Note that we are using more of a C++ style for these and not the getXxxxx format used in the text book:

std::string name() const;
std::string phoneNumber() const;
std::string email() const;

You must also allow updates to the phoneNumber and email values. Note you cannot change the name member data.

void phoneNumber(const std::string &newNumber);
void email(const std::string &newEmail);

Here are the requirements for the phoneBook class

The phoneBook class will be using the std::vector class and will store a collection of phoneBookEntry objects.

The phoneBook class needs to have a default constructor.

In addition it will need the following public member functions:

The insert operations will add the phoneBookEntry to the collection if it does not already exist. The new entry will be added to the bottom of the vector. If the entry already exists (the name is already in the phone book), the existing entry must be updated.

The first version of the insert takes an existing phoneBookEntry and add it to the vector. For the 2nd and 3rd versions of the insert your insert member functions will have to create the phoneBookEntry that is to be added to the collection. These can be temporary phoneBookEntry objects (the copy constructor will be called when the actual entry is added to the vector).

If the entry (name) already exists in the vector you should update the phoneNumber and email for the existing entry.

void insert(const phoneBookEntry &entry);
void insert(const std::string &name, const std::string &number, const std::string &email);
void insert(const std::string &name, const std::string &number);

The erase operation will remove the phone book entry with the associated name from the collection.

bool erase(std::string name);

Your erase function will need to find the entry to be erased. Lets say it is at index i. If there is an entry at i+1 it will need to be moved to entry i. If there is an entry at index i+2 it will need to be moved to entry i+1. This will continue until there are no more entries in the vector. The last entry in the vector will then be deleted (since a copy was put into the entry above it). You should use the erase member function of the std::vector class to do this.

Here are some before and after vectors:

Before

index entry values
0 Bob Smith, 555-555-1111, bobsmith@example.com
1 Ann Jones, 555-555-2222, ajones8383@example.org
2 Sam Gonner, 555-555-9876, sammy.g.9876@example.net
3 Sally Smart, 555-555-9999, sallys@example.com
4 Glinda The Good, 555-555-3333, good@example.com

Remove Sam Gonner

After

index entry values
0 Bob Smith, 555-555-1111, bobsmith@example.com
1 Ann Jones, 555-555-2222, ajones8383@example.org
3 Sally Smart, 555-555-9999, sallys@example.com
4 Glinda The Good, 555-555-3333, good@example.com

The erase member function must return true if the entry was erased and false if it was not erased (because it doesn't exist).

The find member function will determine if there is a phoneBookEntrywith the specified name in the collection. It will return true if it is found and false if it is not found.

bool find(std::string name);

The two print functions will print out the contents of the phoneBook. One will output to cout and the other will output to the passed in ostream object (passed by reference).

void print() const;
void print(std::ostream &out) const;

For the print member functions you must output all of the data left justified in the following format (this is for a phoneBook with three entries):

Name: Phone Number: E-Mail:
John Smith 800-555-1111 john.smith@example.com
Sue Jones 888-555-9876 sjones@example.net
Tommy Tell 888-555-1234 t.tell@example.org

Note that the Name: column is 31 characters wide, and the Phone Number: column is 16 characters wide. The E-Mail: column should not have a predetermined wide as it is at then end of the output. Note that your column titles and column widths MUST look like this.

You should also have a debug member function. It should output the contents of the vector. You can output any additional information you would find helpful in debugging.

void debug(std::ostream &out) const;

The size member function will return the currently number of entries in the phoneBook.

std::size_t size() const;

We want to make use of iterators. The vector class already has support for iterators, so we are going to leverage that to implement out iterator. The iterator support will allow us to use the range based for loop with our phoneBook class.

You need to include the following in your phoneBook class declaration:

typedef std::vector< phoneBookEntry> phoneBookEntryList;
typedef phoneBookEntryList::iterator iterator;
typedef phoneBookEntryList::const_iterator const_iterator;
iterator begin();
iterator end();

Note that the above creates a typedef named phoneBookEntryList that is actually the type std::vector< phoneBookEntry>. So you can create your phone book vector as follows in the phoneBook class.

phoneBookEntryList book;

The actual type of book will be std::vector< phoneBookEntry>.

The begin member function needs to call the vector's begin member function, and the end member function needs to call the vector's end member function.

Note that the typedef statements are inside of the phoneBook class declaration. If you make use of them outside of the class definition you will have to use the syntax phoneBook::iterator (as an example) to get access to them.

This will be required if you implement begin or end in your phoneBook.cpp file:

phoneBook.cpp

...

phoneBook::iterator phoneBook::begin()
{
// your code goes here
}
...

Subclass of command

First you need to create a new class bookCommand that publicly inherits from command. You will not be implementing the execute pure virtual function, so the new class bookCommand will also be an abstract class.

The bookCommand class should have two protected data members. One is a reference to std::istream, and the second one is a reference to std::ostream. See demo classes incrementCommand and decrementCommand to see how to do this using a reference to an int.

The constructor for the bookCommand class should be:

bookCommand(std::istream &in, std::ostream &out);

Your constructor should save these parameters (all passed by reference) in the protected data members in your class (for the std::istream and std::ostream references).

When you code the bookCommand constructor you will need to use an initialization list. Assume the following are defined in your bookCommand.h file:

protected:
std::istream ∈
std::ostream &out;

Here is the constructor in the .cpp file (the initialization list would be used even if the constructor is inlined):

bookCommand::bookCommand(std::istream &inStream, std::ostream &outStream)
: in(inStream), out(outStream)
{
// other code, if any, goes here
}

The in(inStream) syntax is showing the actual parameter (inStream) being used to construct the std::istream &in object.

You should also have two protected member functions.

One will display a passed in std::string to the std::ostream that was passed to you on the constructor. This function does not return a value, it takes one parameter of type std::string and display it to the std::ostream protected reference.

The second member function will be passed in a std::string that will be written to the std::ostream passed to your constructor. This is a prompt to the user. It will then read in a std::string from the std::istream passed to your constructor and return the read in std::string to the caller. Note that the input you are reading in may contain embedded spaces. For this reason you should (must) use getline to read in the input values.

These two helper function will be used by the addUpdateCommand, eraseCommand, and printCommand subclasses of bookCommand.

Subclasses of bookCommand

You need to create three subclasses of your new abstract class bookCommand. They will make use of the two protected member functions you created for the bookCommand class. The subclasses will also have access to the std::istream and std::ostream objects references that are protected data members in the bookCommand class. You should use public inheritance for the subclasses of bookCommand.

class addUpdateCommand

This class needs a constructor that takes a reference to a phoneBook, a reference to a std::istream and a reference to a std::ostream. It will need to pass the std::istream and std::ostream references to the bookCommand constructor. The phoneBook reference needs to be saved in a private data member of class addUpdateCommand. For the addUpdateCommand constructor will need to use initialization lists. This will also be true for the eraseCommand and printCommand classes.

Here is an example of the constructor for the addUpdateCommand class

addUpdateCommand::addUpdateCommand(phoneBook &bookIn, std::istream &inStream, std::ostream &outStream)
: bookCommand(inStream, outStream), book(bookIn)
{
// any other code you may need
}

First we call the constructor for the bookCommand class we inherit from. We pass it the istream and ostream references passed on our constructor. Next we specify the constructor for our instance variable book which is of type phoneBook &. You many have called the reference something different. Just use the reference name you coded in your addUpdateCommand class.

You also need to override the execute member function you inherited from command. In the execute you need to user the bookCommand member functions to prompt for the name, phone number and email. You also need to issue the appropriate error messages (again using the member function from bookCommand). See the sample output below for examples of the prompts and error messages required for this application. You will delegate the actual add/update to the phoneBook class. Note that all input and output performed by addUpdateCommand should be performed using the helper functions you wrote for the bookCommand class.

Here is the sample output from the addUpdateCommand for a valid add:

Enter name to add/update
John Smith[Enter]
Enter phone number
555-999-3333[Enter]
Enter e-mail address
john.smith.876343@example.com[Enter]
Adding phone book entry for John Smith

NOTE: The data followed by [Enter] is entered by the application users, the rest is displayed by the member functions in the boookCommand class.

Here is the sample output from the addUpdateCommand for a valid update:

Enter name to add/update
John Smith[Enter]
Enter phone number
555-555-9876[Enter]
Enter e-mail address
john.smith.9876@example.net[Enter]
Updating phone book entry for John Smith

NOTE: The data followed by [Enter] is entered by the application users, the rest is displayed by the member functions in the boookCommand class.

class eraseCommand

You need the same constructor signature you used in the addUpdateCommand class. You will need to override the execute member function and prompt for name of the phoneBookEntry to be erased. See the sample output below for examples of the prompts and error messages required for this application.

You will delegate the actual erase to the phoneBook class. Note that all input and output performed by eraseCommand should be performed using the helper functions you wrote for the bookCommand class. Here is sample output from the eraseCommand for an entry that exists

Enter name to erase
John Smith[Enter]
Phone book entry John Smith was erased

NOTE: The data followed by [Enter] is entered by the application users, the rest is displayed by the member functions in the boookCommand class.

Here is sample output from the eraseCommand for an entry that does NOT exist

Enter name to erase
John Jones[Enter]
Phone book entry Jerry Jones was not erased

NOTE: The data followed by [Enter] is entered by the application users, the rest is displayed by the member functions in the boookCommand class.

class printCommand

You will have the same type of constructor as you had for addUpateCommand and eraseCommand. The overridden execute command will use the phoneBook print(std::ostream &) member function to display the contents of the phoneBook. The value for std::ostream should be the ostream object saved in the protected state for the bookCommand class.

Here is the output for the printCommand for a phoneBook with three entries

Name: Phone Number: E-Mail:
John Smith 800-555-1111 john.smith@example.com
Sue Jones 888-555-9876 sjones@example.net
Tommy Tell 888-555-1234 t.tell@example.org

This is output from the phoneBook print member function that is called by the printCommand.

assignment2.cpp

This is your main function. Your main will need to create the phoneBook and menuList objects. It will also have to create the addUpdateCommand, eraseCommand, and printCommand objects. Using these you can create the menuItem objects for each of the commands, add them to the menuList and start the menu.

Here is a summary of the three required menuItem objects:

char description command type
a add/update addUpdateCommand
e erase eraseCommand
p print printCommand

Here is the output from the addUpdateCommand for a valid add:

Enter name to add/update
John Smith[Enter]
Enter phone number
555-999-3333[Enter]
Enter e-mail address
john.smith.876343@example.com[Enter]
Adding phone book entry for John Smith

NOTE: The data following by [Enter] is entered by the application users, the rest is displayed by the member functions in the boookCommand class. This is going to take a while to get working, so get started right away.

Do not use any global variables in your program.

First create the phoneBookEntry class and make sure that is working. You may have to create some test code to make sure it is working. Try out the various constructors (including the copy constructor), and the accessors and mutators

Next get the phoneBook working. Start with the constructors and then add the debug support. Next start doing the various insert operations, the erase operation, the find operation, and the print operations. Don't try and do this all at once.

You may want to write some more test code to try out all of the parts of the phoneBook class.

For the menu you can start by getting the menu to work with just the default quit command.

Next you can implement the add/update command and get that working.

After that is working you can add the print support.

Finish by adding the erase.

By doing this incremental development you will have a better idea which function is failing (because it is probably the code you just wrote). Also, make sure you test and fix a member function before you go onto the next one.

Use good formatting in your programs. Use meaningful variable names and comment your code - what do you want to remember about the code when you use these classes in a future lab assignment?

Make sure you test all of this thoroughly.

Here is a sample run (the text [Enter] is used for data typed in by the application user)

Starting the Phone Book

Phone book menu:
a add/update
e erase
p print
q exit the menu
a[Enter]
Enter name to add/update
Bob Smith[Enter]
Enter phone number
888-555-1111[Enter]
Enter e-mail address
bob.smith@example.com[Enter]
Adding phone book entry for Bob Smith

Phone book menu:
a add/update
e erase
p print
q exit the menu
a[Enter]
Enter name to add/update
Sally Jones[Enter]
Enter phone number
800-555-222[Enter]
Enter e-mail address
[Enter]
Adding phone book entry for Sally Jones

Phone book menu:
a add/update
e erase
p print
q exit the menu
p[Enter]
Name: Phone Number: E-Mail:
Bob Smith 888-555-1111 bob.smith@example.com
Sally Jones 800-555-222

Phone book menu:
a add/update
e erase
p print
q exit the menu
e[Enter]
Enter name to erase
Bob Smith[Enter]
Phone book entry Bob Smith was erased

Phone book menu:
a add/update
e erase
p print
q exit the menu
a[Enter]
Enter name to add/update
Sally Jones[Enter]
Enter phone number
800-555-9898[Enter]
Enter e-mail address
sally@example.com[Enter]
Updating phone book entry for Sally Jones

Phone book menu:
a add/update
e erase
p print
q exit the menu
p[Enter]
Name: Phone Number: E-Mail:
Sally Jones 800-555-9898 sally@example.com

Phone book menu:
a add/update
e erase
p print
q exit the menu
q[Enter]

Your output MUST match the above exactly for the same input values.

Academic Honesty!
It is not our intention to break the school's academic policy. Posted solutions are meant to be used as a reference and should not be submitted as is. We are not held liable for any misuse of the solutions. Please see the frequently asked questions page for further questions and inquiries.
Kindly complete the form. Please provide a valid email address and we will get back to you within 24 hours. Payment is through PayPal, Buy me a Coffee or Cryptocurrency. We are a nonprofit organization however we need funds to keep this organization operating and to be able to complete our research and development projects.