Multiple Inheritance Assignment with Refactoring 6 points each 1- Given base code of re-factoring, add the re-factored code. See the example of refactored source code in WebCT 2- Given this base of code, create multiple inheritance. - Create a Singing Waiter class which inherits from Singer and Waiter - Create set(), show() methods with the proper constructors for SingingWaiter - Verify you set and show a Singing Waiter - Remove double data display problems The queue template has tests with CppUnit to illustrate application testing. // main.cpp -- queue template // compile with workers.cpp, mystring.cpp, queue.h #include using namespace std; #include #include "workers.h" #include "queue.h" int main() { // queue stores Worker pointers to make calls dynamically QueueTp lolas; Worker *worker; // helper variable while (1) { char choice; cout << "Enter the employee category:\n" << "w: waiter s: singer " << "t: singing waiter q: quit\n"; cin >> choice; while ( strchr("wstq", choice) == NULL ) { cout << "Please enter a w, s, t, or q: "; cin >> choice; } if (choice == 'q') break; // allocate Worker objects and add them to queue switch(choice) { case 'w': worker = new Waiter; lolas.enqueue(worker); break; case 's': worker = new Singer; lolas.enqueue(worker); break; // Uncomment this code when you have it written // case 't': worker = new SingingWaiter; // lolas.enqueue(worker); // break; default : exit(1); } cin.get(); worker->set(); if ( lolas.isfull() ) break; } // display information on all workers in the queue cout << "\nHere is your staff:\n"; int index; const int LAST = lolas.count(); for (index = 0; index < LAST; index++) { cout << '\n'; lolas.dequeue(worker); worker->show(); delete worker; } cout << "Bye.\n"; return 0; } // mystring.h -- fixed and augmented string class definition #include using namespace std; #ifndef MYSTRING_H_ #define MYSTRING_H_ class String { // overloaded operator friends friend bool operator<(const String &first, const String &second); friend bool operator>(const String &first, const String &second); friend bool operator==(const String &first, const String &second); friend ostream & operator<<(ostream & os, const String & string); friend istream & operator>>(istream & is, String & string); public: enum { CIN_INPUT_LIM = 80 }; // constructors String(const char * buffer); String(); String(const String & string); ~String(); int length () const { return len; } // overloaded operator methods String & operator=(const String & string); String & operator=(const char * buffer); char & operator[](int index); const char & operator[](int index) const; // static functions static int how_many(); private: char * str; // pointer to string int len; // length of string static int num_strings; // number of objects }; #endif // mystring.cpp -- String class methods #include #include #include "mystring.h" using namespace std; // initializing static class member int String::num_strings = 0; // static method int String::how_many() { return num_strings; } // class methods // construct String from C character buffer String::String(const char * buffer) { len = strlen(buffer); str = new char[len + 1]; strcpy(str, buffer); num_strings++; } // The default string is empty String::String() { len = 0; str = new char[1]; str[0] = '\0'; num_strings++; } String::String(const String & string) { num_strings++; len = string.len; str = new char [len + 1]; strcpy(str, string.str); } String::~String() { --num_strings; delete [] str; } // overloaded operator methods // assign a String to a String String & String::operator=(const String & string) { if (this == &string) return *this; delete [] str; len = string.len; str = new char[len + 1]; strcpy(str, string.str); return *this; } // assign a C string buffer to a String String & String::operator=(const char * buffer) { delete [] str; len = strlen(buffer); str = new char[len + 1]; strcpy(str, buffer); return *this; } // read-write char access for non-const String char & String::operator[](int index) { return str[index]; } // read-only char access for const String const char & String::operator[](int index) const { return str[index]; } // overloaded operator friends bool operator<(const String &first, const String &second) { return (strcmp(first.str, second.str) < 0); } bool operator>(const String &first, const String &second) { return second.str < first.str; } bool operator==(const String &first, const String &second) { return (strcmp(first.str, second.str) == 0); } // simple String output ostream & operator<<(ostream & os, const String & string) { os << string.str; return os; } // quick and dirty String input istream & operator>>(istream & is, String & string) { char temp[String::CIN_INPUT_LIM]; is.get(temp, String::CIN_INPUT_LIM); if (is) string = temp; while (is && is.get() != '\n') continue; return is; } #ifndef QUEUE_H_ #define QUEUE_H_ // queue.h -- interface for a queue template // This queue will contain any object template class QueueTp { public: enum {DEFAULT_Q_SIZE = 10}; // create queue with a size limit QueueTp(int size = Q_SIZE) : QSIZE(size); ~QueueTp(); bool isempty() const; bool isfull() const; int count() const; // add item to end bool enqueue(const Type &item); // remove item from front bool dequeue(Type &item); private: struct Node { Type item; struct Node * next; }; Node * front; Node * rear; int items; const int QSIZE; // preemptive definitions to prevent public copying QueueTp(const QueueTp & q) : QSIZE(0) { } QueueTp & operator=(const QueueTp & q) { return *this;} }; // QueueTp methods template QueueTp::QueueTp(int size) { front = rear = NULL; items = 0; } template QueueTp::~QueueTp() { Node * temp; while (front != NULL) // while queue is not yet empty { temp = front; // save address of front item front = front->next;// reset pointer to next item delete temp; // delete former front } } template bool QueueTp::isempty() const { return items == 0; } template bool QueueTp::isfull() const { return items == QSIZE; } template int QueueTp::count() const { return items; } // Add item to queue template bool QueueTp::enqueue(const Type & item) { if (isfull()) return false; Node * add = new Node; // create node if (add == NULL) return false; // quit if none available add->item = item; // set node pointers add->next = NULL; items++; if (front == NULL) // if queue is empty, front = add; // place item at front else rear->next = add; // else place at rear rear = add; // have rear point to new node return true; } // Place front item into item variable and remove from queue template bool QueueTp::dequeue(Type & item) { if (front == NULL) return false; item = front->item; // set item to first item in queue items--; Node * temp = front; // save location of first item front = front->next; // reset front to next item delete temp; // delete former first item if (items == 0) rear = NULL; return true; } #endif #ifndef WORKERS_H_ #define WORKERS_H_ // workers.h -- working classes with MI #include "mystring.h" // an abstract base class class Worker { public: Worker() : fullname("no one"), id(0L) {} Worker(const String & name, long id) : fullname(name), id(id) {} virtual ~Worker() = 0; // pure virtual function virtual void set() = 0; virtual void show() const = 0; private: String fullname; long id; }; // Change this class for double vision problems // Use virtual keyword for the class declaration // Change the way you set and show data class Waiter : public Worker { public: Waiter() : Worker(), panache(0) {} Waiter(const String & name, long id, int panache = 0) : Worker(name, id), panache(panache) {} Waiter(const Worker & worker, int panache = 0) : Worker(worker), panache(panache) {} void set(); void show() const; private: int panache; }; // Change this class for double vision problems // Use virtual keyword for the class declaration // Change the way you set and show data class Singer : public Worker { public: enum {OTHER, ALTO, CONTRALTO, SOPRANO, BASS, BARITONE, TENOR}; enum {RANGE_MAX = 7}; // Descriptive words for singer's range static char *range[RANGE_MAX]; Singer() : Worker(), voice(other) {} Singer(const String & name, long id, int voice = other) : Worker(name, id), voice(voice) {} Singer(const Worker & worker, int voice = other) : Worker(worker), voice(voice) {} void set(); void show() const; private: int voice; }; // Add a SingingWaiter Class which multiply inherits from // Singer and Waiter // Create set() and show() methods // Create appropriate constructors // CODE UP THE SingingWaitor class here #endif // workers.cpp -- working class methods with MI #include "workers.h" #include using namespace std; // Worker methods Worker::~Worker() { } // protected methods void Worker::show() const { cout << "Name: " << fullname << "\n"; cout << "Employee ID: " << id << "\n"; } void Worker::set() { cin >> fullname; cout << "Enter worker's ID: "; cin >> id; while (cin.get() != '\n') continue; } // Waiter methods void Waiter::set() { cout << "Enter waiter's name: "; Worker::set(); cout << "Enter waiter's panache rating: "; cin >> panache; while (cin.get() != '\n') continue; } void Waiter::show() const { cout << "Category: waiter\n"; Worker::show(); cout << "Panache rating: " << panache << "\n"; } // Singer methods char * Singer::range[Singer::RANGE_MAX] = {"other", "alto", "contralto", "soprano", "bass", "baritone", "tenor"}; void Singer::set() { cout << "Enter singer's name: "; Worker::set(); cout << "Enter number for singer's vocal range:\n"; int index; for (index = 0; index < RANGE_MAX; index++) { cout << index << ": " << range[index] << " "; if ( index % 4 == 3) cout << '\n'; } if (index % 4 != 0) cout << '\n'; cin >> voice; while (cin.get() != '\n') continue; } void Singer::show() const { cout << "Category: singer\n"; Worker::show(); cout << "Vocal range: " << range[voice] << "\n"; } // SingingWaiter methods // CODE UP set() and show() for a SingingWaiter here