OOP244 Final Project (v. 3.0) Seneca Course Management Tool (SCM)


1 Summer 2016

OOP244 Final Project (v. 3.0)

Seneca Course Management Tool (SCM)

You are asked to develop a C++ application that manages Seneca courses taken by the students at the School of Information and Communications Technology (ICT). In this proof of concept application, the ICT students can take two types of courses, namely ICT-related courses (e.g. OOP244, BTP200) and general education courses (e.g. EAC150, BTC140). The application will provide a console-based menu system to manage these courses. You will develop this application incrementally as new user requirements emerge during the project development process. As you work on the project, you will build up your conceptual and practical knowledge of object-oriented programming in C++. You will learn to apply three principles of object-oriented programming (i.e. encapsulation, inheritance and polymorphism). In particular, you will create five classes as new user requirements emerge. The application class will be the point of integrating four classes. A. THE USER INTERFACE Seneca Course Management Tool 1- List courses. 2- Display the details of a course. 3- Add a course. 4- Change the study load of a course. 5- Load courses from a file. 6- Save courses to a file. 0- Exit program. > _ 2 B. CLASSES TO BE DEVELOPED You will develop the following five classes for this application: Streamable This interface (a class with “only” pure virtual functions) enforces that the classes inherited from it are to be “streamable”. In the first half of the course we define streams to be sequence of characters. IO streams allow program data to be exchanged with peripherals such as computer consoles or keyboards. Any class derived from “Streamable” can read from or write to streams. Using this class, a list of courses can be saved to and retrieved from a file. Individual course details can be displayed on screen or read from keyboard. Course A class that encapsulates information about courses. As the project develops, this class will acquire streamable characteristics as new user requirements emerge. ICTCourse A class that encapsulates information about ICT-related courses (e.g. OOP244, BTP200). It is derived from the Course class. GenEdCourse A class that encapsulates information about general education courses (e.g. EAC150, BTC140). It is derived the Course class. ScmApp An application class that provides a console-based menu system to manage The courses. It will use the other four classes in order to provide the system’s functionality. You will develop this application incrementally as new user requirements emerge. C. CLASS DIAGRAM 3 D. PROJECT DEVELOPMENT PROCESS You have approximately four weeks to complete the project. The project is divided into 4 milestones and thus four deliverables. Each milestone has a clear learning focus and specific learning tasks. The approximate schedule for the deliverables is as follows: • Final Project Due date: Friday August 12, 2016 by 11:59:00pm. • MS1: The Course and ScmApp classes. Due: July 27, 2016 (30% of grade) • MS2: The ICTCourse, GenEdCourse and Due: August 5, 2016 (30% of grade) ScmApp classes. • MS3: The Streamable, Course, ITCourse Due: August 9, 2016 (30% of grade) and GenEdCourse classes. • MS4: Completion of the ScmApp class. Due: August 12, 2016 (10% of grade) You must submit each milestone by the due date indicated. A 10% penalty (for the particular milestone missed) will be assessed for each day late. E. FILE STRUCTURE OF THE PROJECT Each class will have its own header file and .cpp file. The names of these files should be the same as the class names. Example: Class Course has two files: Course.h and Course.cpp In addition to header files for each class, create a header file called “general.h” that will hold the general defined values for the project, such as: MAX_COURSECODE_LEN (6) The maximum length of a course code. DISPLAY_LINES (10) The maximum number of lines used to display course details before each pause. MAX_NO_RECS (2000) The maximum number of records in the data file. This header file should get included where these values are used. Notes 1. All the code developed for this application should be in the sict namespace. 2. All the code must be properly documented and indented. Ask your instructor for details. 4 MILESTONE 1: TWO CLASSES (Course and ScmApp). Learning Focus: Dynamic Memory Allocation; Operator Overloading. Learning Tasks: 1. Create the Course and ScmApp classes according to user requirements. 2. Test the Course and ScmApp classes. A. User Requirements Create a class called Course. The class Course is responsible for encapsulating information about general courses at Seneca College. At Milestone 1, this class is a concrete class. It will become an abstract base class at Milestone 3. The class is implemented under the sict namespace. Code the Course class in Course.h and Course.cpp. 1. The Course Class Specs. Private Member Variables. courseCode_: Character array, MAX_COURSECODE_LEN + 1 characterslong. This character array holds the course code as a string. courseTitle_: Character pointer This character pointer points to a dynamic string that holds the title of the course. credits_: Integer It holds the number of credits of the course. studyLoad_: Integer It hold the amount of study load, defined by the number of assignments. Public Member Functions and Constructors No Argument Constructor This constructor sets the Course object to a safe recognizable empty state. All number values are set to zero in this state. 5 Four Argument Constructor The Course object is constructed by passing 4 values to the constructor: the course code, the course title, the number of credits and the amount of study load. The constructor: • Copy the course code into the corresponding member variable up to MAX_COURSECODE_LEN characters. • Allocate enough memory to hold the name as pointed by the pointer courseTitle_. Then copy the name into the allocated memory pointed to by the member variable courseTitle_. • Set the rest of the member variables to the corresponding values received by the arguments. You should ensure that the data passed in is valid. If any of the data is invalid, you should set the object to the empty state. Validation criteria – course code – must be non-empty and must not be long than MAX_COURSECODE_LEN characters – course title – must be non-empty – the number of credits – non-negative (greater than 0) – study load – non-negative (greater than 0) Copy Constructor See below. Dynamic Memory Allocation Requirements Implement the copy constructor and the operator= so the Course object is copied from and assigned to another Course object safely and without any memory leak. (Also implement a destructor to make sure that the memory allocated by the pointer courseTitle_ is freed when the Course object is destroyed 6 Setters: Create the following setter functions to set the corresponding member variables: void setCourseCode(const* char cc) void setCourseTitle(const* char ct) void setCredits(int c) void setStudyLoad(int sl) Validate the input to ensure that the setter function cannot invalidate the object. Use the validation rules stated in the constructor section. If the input is invalid, do not allow the member to be modified. No other action is required. All the above setters return void. Getters (Queries): Create the following constant getter functions to return the values or addresses of the corresponding member variables: (these getter functions do not receive any arguments) – getCourseCode(), returns constant character pointer – getCourseTitle(), returns constant character pointer – getCredits(), returns integer – getStudyLoad(), returns integer Also: – isEmpty returns bool isEmpty returns true if the Course object is in a safe empty state, false otherwise All the above getters are constant functions, which means that they CANNOT modify the current object. Overload Member Operators. Operator== : receives a constant character pointer and returns a boolean. This operator will compare the received constant character pointer to the course code of the course, if they are the same, it will return true. Otherwise it will return false. Operator+= : receives an integer and returns an integer. This operator will change the received integer value to the study load of the course, returning the sum. Note: A negative integer is used to reduce the study load. 7 Overload the ostream operator << (a free helper function). After implementing the Course class, overload the ostream operator<< as a free helper function. Hint: You should implement a public member function called display( ). It displays the data values of a Course object in the following format (separated by Bar “|” characters ) : OOP244 | OOP In C++ | 1 | 3 | course code: left justified, MAX_COURSECODE_LEN characters course title: left justified, 20 characters wide (truncated if longer than 20 chars) credits: right justified, 6 characters wide study load: right justified, 4 characters wide NO NEW LINE CHARACTER Note: Each Bar “|” character is surrounded by two blank spaces Make sure that the prototypes of the functions are in Course.h. 8 2. The ScmApp Class Specs. The ScmApp class provides a console-based menu system to manage the courses. Code the class in ScmApp.h and ScmApp.cpp. Private member variables. Course* courseList_[MAX_NO_RECS]; An array of Course pointers. The size of this static array is MAX_NO_RECS. Note: Each element of this array is a Course pointer. Reminder: MAX_NO_RECS is defined in in the header file general.h. int noOfCourses_; The number of courses (ICTCourse or GenEdCourse) that are currently pointed by the array courseList_. 9 The Constructor. The no-argument ScmApp constructor does the following initialization: 1- Set all the courseList_ elements to nullptr. 2- Set noOfCourses_ to zero. Private member functions. The Copy Constructor and Assignment Operator. Make sure that an ScmApp object cannot get copied or assigned to another ScmApp object. void pause() const; It prints: “Press Enter to continue…” and then waits for the user to hit enter. If user hits any other key, the key in ignored. Only ENTER will terminate this function. int menu(); It displays the menu as follows and waits for the user to select an option. Seneca Course Management Tool 1- List courses. 2- Display the details of a course. 3- Add a course. 4- Change the study load of a course. 0- Exit program > _ ^ here is where the cursor stands when menu is printed – If the selection number is valid, the member function menu( ) will return the selection. Otherwise it will return -1. – This function makes sure that there are no characters left in the keyboard buffer and wipes it clean before exit. void listCourses()const; – It displays the details of all courses. First, it displays the following title : Row | Code | Course Title | Credits | Study Load | —–|——|————————|———-|———–| – Then it iterates through the array courseList_ up to noOfCourses_ and displays the following for each course • Row number in four spaces right justified • a Bar character (|) surrounded by two spaces. 10 Then it displays the current Course in the iteration followed by a newline – If the Row number reaches to 10, the program will pause. – At the end of the iteration, it will close the list with the following dotted line: ————————————————————————— int searchForACourse(const char* courseCode)const; Iterates through the array courseList_ up to noOfProducts_ and checks each array element for the same course code as the incoming argument using the operator== implemented for the Course class. If a match is found, it will return the index of the found Course in the array courseList_. Otherwise it will return -1. void changeStudyLoad(const char* courseCode); It changes the study load of a course whose course code matches courseCode as the incoming argument. If not found it will display: “Not found!” If found, it will ask for an integer for the amount of study load: “Please enter the amount of the study load: ” It uses the operator += (overloaded in the Course class) to change the study load of the course. Make sure that the keyboard is flushed after the data entry. void addACourse(); It gets the data values from the user to initialize the object. Finally it adds the object address to the end of the array courseList_. 11 Public member functions int run(); It displays the menu and processes user requests. Depending on the user’s selection number, it performs the action as requested and pauses. (Use the pause function.) Then it redisplays the menu until the user selects zero to exit. 1- List courses. List all the courses. 2- Display the details of a course. Ask for a course code using this prompt “Please enter the course code: ” and get it from the console. Then search for it. If found, display the course details. Otherwise display: “Not found!” 3- Add a course. It calls the addACourse() function. 4- Change the study load of a course. Ask for a course code using this prompt “Please enter the course code: ” and get it from the console. Then call the changeStudyLoad() function. 0- Exit program The program will terminate printing: “Goodbye!!” In case of an invalid menu selection the program will print: “===Invalid Selection, try again.===”. Then it will pause before redisplaying the menu. The function run( ) returns 0 at the end. 12 MILESTONE 2: TWO NEW CLASSES (ICTCourse, GenEdCourse). Learning Focus: Inheritance and Polymorphism. Learning Tasks 1. Create two classes (ICTCourse, GenEdCourse) that are derived from the class Course. 2. Modify the class Course in order to implement the inheritance hierarchy successfully. 3. Modify the application class ScmClass with the following functionality: – List courses. – Display the details of a course. – Add a course. (Note: Add an ICT course or a GenEdCourse.) – Change the study load of a course. A. User Requirements. 1. Course Class Modify the Course class so it becomes an abstract base class. Make Course::display() a pure virtual function. 2. General.h file Add the following constants TYPE_GEN = ‘G’ TYPE_ICT = ‘I’ 3. The ICTCourse Class Specs. Implement the ICTCourse class in ICTCourse.h and ICTCourse.cpp as a class derived from the Course class. Private member variables char computerSystem_[6+1]; It holds the type of computer system that will be used in an ICT course (e.g. matrix, oracle, as400, win and linux). 13 Public Constructors The ICTCourse class has two constructors. The no-argument constructor sets the object to the safe empty state defined for Course in milestone 1. The five-argument constructor receives four arguments for the course code, the course title, the number of credits and the amount of study load (i.e. the data members of the base class). It receives a string as the fifth argument to initialize the member variable computerSystem_. Truncate the fifth argument to 6 characters if necessary. The default value for the fifth argument is “matrix.” 14 Public Member Functions const char* getComputerSystem() const; It returns a constant pointer to the computerSystem_ member variable. void setComputerSystem (const char* value); It copies the incoming value string into the member variable computerSystem_ . Make sure that the copying does not pass the size of the array computerSystem_. This implies that truncation is used if necessary. Overload the ostreram operator << (a FREE helper function): Reuse the ostream operator<< from Milestone 1. Hint: In order to have polymorphic behavior, you should implement a virtual function called display(std::ostream) and reuse the function display(std::ostream) in the base class. The function displays the data values an ICTCourse object in the following format (separated by the bar “|” character and two padding spaces on each side, except for the last one): OOP244 | OOP | 1 | 4 | matrix | | 123456__|__12345678901234567890__|__123456__|__1234__|__123456__|__1234__| course code: as specified in Milestone 1 course title: as specified in Milestone 1 credits: as specified in Milestone 1 study load: as specified in Milestone 1 system: left-justified, 6 characters wide (truncated if longer than 6 characters) empty field: 4 characters wide NO NEW LINE CHARACTER 4. The GenEdCourse Class Specs. Implement the GenEdCourse class in GenEdCourse .h and GenEdCourse.cpp as a class derived from the Course class. Private Member Variables. The GenEdCourse class has one private member variable: • langLevel_ : Integer It holds the English language requirement. This must be a value between 0 and 5. Constructor. GenEdCourse has two constructors. 15 The five-argument constructor receives four arguments for the course code, the course title, the number of credits and the amount of study load (i.e. the data members of the base class). It receives a integer as the fifth argument to initialize the member variable langLevel_. The default value for the fifth argument is 0. Public Member Functions. int getLangLevel() const; It returns the value of the member variable langLevel_. void setLangLevel (int value); It copies the incoming integer value into the member variable langLevel_ if the value is between 0 and 5. If the value is not within the range, do NOT update the variable. No other action is required. Overload the ostream operator << (a FREE helper function). After implementing the GenEdCourse class, overload the ostream operator << as a free helper function. Hints: You should implement a public member function called display( ) and reuse the function display( ) in the base class. The function displays the data values of an GenEdCourse object as shown below (separated by the bar “|” character and two padding spaces on each side, except for the last one): EAC150 | College English | 1 | 4 | | 0 | 123456__|__12345678901234567890__|__123456__|__1234__|__123456__|__1234__| course code: as specified in Milestone 1 course title: as specified in Milestone 1 credits: as specified in Milestone 1 study load: as specified in Milestone 1 a field with 6 blank spaces language requirement: right justified, 4 characters wide NO NEW LINE CHARACTER 3. Modify the application class (ScmApp). a) Modify the application class such that the menu system can be used to add two types of courses, namely ICT-related courses and general education courses. 3- Add a course. Ask the user for a course type. Ask for a course type using this prompt : “Please enter the course type (I-ICT or G-GenEd): ” 16 and get it from the console. Then call the addACourse() function. b) Modify the addACourse( ) function such that it receives an character as a parameter. Use the constant chars TYPE_GEN and TYPE_ICT defined in the general.h file. TYPE_ICT means that an ICTCourse object will be added. TYPE_GEN means that a GenEdCourse object will be added. It gets the data values from the user to initialize an ICTCourse or GenEdCourse object. You should use the following order to get input values for an ICTCourse object. Course Code: OOP244 Course Title: OOP in C++ Credits: 1 Study Load: 4 Computer System: oracle You should also use the following order to get input values for a GenEdCourse object. Course Code: EAC150 Course Title: College English Credits: 1 Study Load: 4 Language Requirement: 12 MILESTONE 3: THE STREAMABLE INTERFACE , ABSTRACT BASE CLASS AND OBJECT SERIALIZATION. In this milestone, the Course class and its derived classes will acquire streamable characteristics. As a result, the Streamable interface is provided to enforce that all concrete classes on the inheritance hierarchy will implement functions that work with fstream and iostream objects. In other words, the ICTCourse and GenEdCourse classes have the capability of doing object serialization (i.e. writing an object to a file and reading an object from a file). Code the Streamable interface in the Streamable.h file. It does not have an implementation file. A. User Requirements 1. Pure virtual member functions. The Streamable interface has four pure virtual member functions: 1- fstream& store(fstream& file, bool addNewLine = true) const It is a constant member function (does not modify the owner) and receives and returns references of std::fstream. 2- fstream& load(std::fstream& file) It receives and returns references of std::fstream. 3- ostream& display(ostream& os) const It is a constant member function and returns a reference of std::ostream. It receives one argument: a reference of std::ostream. 4- istream& read(istream& is) It returns and receives references of std::istream. 2. Modify the Course Class. Derive the Course class from the Streamable interface. 3. Modify the ICTCourse Class. ICTCourse implements all four pure virtual functions of the Streamable interface. (Note: The signatures of the functions are identical to those of Streamable.) fstream& ICTCourse::store(fstream& fileStream, bool addNewLine) const Using the ostream operator << , this function first writes the ‘I’ character (defined by TYPE_ICT) and a comma into the argument fileStream. Then, without any formatting or spaces, it writes all the member variables of an ICTCourse object, separated by commas, in the following order: course code, course title, credits, study load, system and a new line character if addNewLine is true. Finally it returns the argument file. Example: I,OOP244,OOP in C++,1,4,matrix fstream& ICTCourse::load(fstream& fileStream) Using the istream operator >>, the ignore( ) and getline( ) functions of istream, this function reads a record from the argument fileStream. It uses setters to set the member variables of the current object. When reading a record, the function assumes that the record does not have the character ‘I’ (defined by TYPE_ICT) at the beginning. Thus it starts reading from the field that has the course code. No error detection is done. At the end the argument fileStream is returned. Hint: Create temporary variables of primitive data types to read the fields one by one, skipping the commas. After reading a field, use a setter to set a member variable of the current object. ostream& ICTCourse::display(ostream& os) const Reuse the function display( ) that has been implemented in this class. istream& ICTCourse::read(istream& istr): It receives data values from an istream object (the argument istr) in the following order: Course Code: OOP244 Course Title: OOP in C++ Credits: 1 Study Load: 4 Computer System: oracle It uses the setters to set the member variables of the current object. Finally it returns the arguments istr. 4. Modify the GenEdCourse Class. GenEdCourse implements all four pure virtual functions of the Streamable interface. (Note: The signatures of the functions are identical to those of Streamable.) fstream& GenEdCourse::store(fstream& fileStream, bool addNewLine) const Using the ostream operator << , this function first writes the ‘G’ character (defined by TYPE_GEN) and a comma into the argument fileStream. Then, without any formatting or spaces, it writes all the member variables of an GenEdCourse object, separated by commas, in the following order: course code, course title, credits, study load, language requirement and a new line character if addNewLine is true. Finally it returns the argument fileStream. Example: I,EAC150,College English,1,4,12 fstream& GenEdCourse::load(fstream& fileStream) Using the istream operator >>, the ignore( ) and getline( ) functions of istream, this function reads a record from the argument fileStream. It uses setters to set the member variables of the current object. When reading a record, the function assumes that the record does not have the character ‘G’ (defined by TYPE_GEN) at the beginning. Thus it starts reading from the field that has the course code. No error detection is done. At the end the argument fileStream is returned. Hint: Create temporary variables of primitive data types to read the fields one by one, skipping the commas. After reading a field, use a setter to set a member variable of the current object. ostream& GenEdCourse::display(ostream& os) const Reuse the function display( ) that has been implemented in this class. istream& GenEdCourse::read(istream& istr): It receives data values from an istream object (the argument istr ) in the following order: Course Code: EAC150 Course Title: College English Credits: 1 Study Load: 4 Language Requirement: 12 It uses the setters to set the member variables of the current object. Finally it returns the argument istr. B. Testing and Submission Requirements (MILESTONE 3). 1. In order for you class to be tested, the following must be done in order for the ScmAppTester class to access the ScmApp class that you have built. a. A forward declaration of the class ScmAppTester must be placed INSIDE the sict namespace AND before the ScmApp definition. b. The ScmTester class must be declared to be a friend of the ScmApp class Your ScmApp.h file should look something like the following. namespace sict{ class ScmAppTester; class ScmApp { private members public: public members friend class ScmAppTester; }; } c. The main() function that you used to test your application must be commented out. 2. If not on matrix already, upload general.h, Course.h, ScmApp.h, ICTCourse.h, GenEdCourse.h, Coures.cpp, ICTCourse.cpp, GenEdCourse.cpp, ScmApp.cpp, Streamable.h to your matrix account. Compile and run your code and make sure everything works properly. Then run the following script from your account: ~eden.burton/submit ms3 and follow the instructions. If your submission is not successful, you can check the output.txt file generated to see which tests fail. 2. If you cannot get your code to pass all tests, you can submit your code for partial marks using the open submitter. This submitter will not be available until after the due date ~eden.burton/submit ms3open

THE END OF MILESTONE

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: