CSCE 2004 - Laboratory Assignment 13

    In the last two labs, we worked on some basic concepts of object oriented programming (defining classes, implementing class methods, and testing classes). The goal of this lab is to show students how multiple classes can be combined to solve larger problems. In particular, we will be creating a "Course" class that contains an array of "Student" objects. Inside the "Student" class, we will be storing the UAID, Name and GPA for a student. Since we do not want to type all of this student information in every time we run the program, these two classes will have methods to read/write student information to/from ASCII files. This lab has the following steps.

  1. Create the Student Class
  2. In this section, we will be creating a "Student" class. This data structure allows the user to store the UAID, Name and GPA for a student. In addition to the constructors and destructor, it has the following methods to input/output student data:

    Step 1: Copy and paste the class interface below into a file called "student.h".

    #include <string>
    #include <fstream>
    #include <iostream>
    using namespace std;
    
    class Student
    {
    public:
       Student();
       Student(const Student & student);
       ~Student();
    
       void Set(const int uaid, const string name, const float gpa);
       void Get(int & uaid, string & name, float & gpa) const;
       void Print() const;
       bool Read(ifstream & input);
    
    private:
       int Uaid;
       string Name;
       float Gpa;
    };
    

    Step 2: Copy and paste the class implementation below into a file called "student.cpp". Notice that this code includes the class interface file "student.h", and all method names start with "Student::" to indicate that they are part of the Student class.

    #include "student.h"
    using namespace std;
    
    Student::Student()
    {
       Uaid = -1;
       Name = "";
       Gpa = -1.0;
    }
    
    Student::Student(const Student & student)
    {
       Uaid = student.Uaid;
       Name = student.Name;
       Gpa = student.Gpa;
    }
    
    Student::~Student()
    {
    }
    
    void Student::Set(const int uaid, const string name, const float gpa)
    {
       Uaid = uaid;
       Name = name;
       Gpa = gpa;
    }
    
    void Student::Get(int &uaid, string & name, float &gpa) const
    {
       uaid = Uaid;
       name = Name;
       gpa = Gpa;
    }
    
    void Student::Print() const
    {
       cout << Uaid << " " << Name << " " << Gpa << endl;
    }
    
    bool Student::Read(ifstream & input)
    {
       return (input >> Uaid >> Name >> Gpa);
    }
    

    Step 3: Compile the Student class using "g++ -Wall -c student.cpp". This will check the syntax of your student.h and student.cpp files and create an output file called "student.o". You can not run this code until we compile and link in a main program.

  3. Create the Course Class
  4. In this section, we will be creating a "Course" class. This data structure contains a fixed size array of "Student" objects and a variable that tells us how much of the array is currently in use. In addition to the constructors and destructor, it has the following methods to input/output student data:

    Step 1: Copy and paste the class interface below into a file called "course.h".

    #include <string>
    #include <fstream>
    #include <iostream>
    #include "student.h"
    using namespace std;
    
    class Course
    {
    public: 
       Course();
       Course(const Course & course);
       ~Course();
    
       void Print() const;
       bool Read(const string filename);
    
    private: 
       static const int MAX_STUDENTS = 100;
       Student students[MAX_STUDENTS];
       int num_students;
    };
    

    Step 2: Copy and paste the class implementation below into a file called "course.cpp". Notice that this code includes the class interface file "course.h", and all method names start with "Course::" to indicate that they are part of the Course class.

    #include "course.h"
    using namespace std;
    
    Course::Course()
    {
       num_students = 0;
    }
    
    Course::Course(const Course & course)
    {
       num_students = course.num_students;
       for (int index = 0; index < num_students; index++)
          students[index] = course.students[index];
    }
    
    Course::~Course()
    {
    }
    
    void Course::Print() const 
    {
       for (int index = 0; index < num_students; index++)
          students[index].Print();
    }
    
    bool Course::Read(const string filename)
    {
       // Open input file
       ifstream din;
       din.open(filename.c_str());
       if (din.fail())
       {
          cerr << "Could not open file: " << filename << endl;
          return false;
       }
    
       // Read student data
       num_students = 0;
       while ((num_students < MAX_STUDENTS) && 
          students[num_students].Read(din))
          num_students++;
       din.close();
       return num_students > 0;
    }
    

    Step 3: Compile the Course class using "g++ -Wall -c course.cpp". This will check the syntax of your course.h and course.cpp files and create an output file called "course.o". You can not run this code until we compile and link in a main program.

    Run the command "ls -l" and copy and paste the output below.

  5. Testing the Student and Course Classes
  6. Your next task will be to create a main program to test the two classes above. This process has four steps.

    Step 1: Copy and paste the code below into a file called "main.cpp". Notice that this file includes "course.h" which includes "student.h". This means that we can define and use Student and Course objects in our main program.

    #include "course.h"
    using namespace std;
    
    int main()
    {
       // Testing Student class
       cout << "Testing Student class\n";
       Student student;
       student.Set(1111, "Joe", 2.5);
       student.Print();
    
       // Testing Course class
       cout << "Testing Course class\n";
       Course course;
       course.Read("csce2004.txt");
       course.Print();
       return 0;
    }
    

    Step 2: To compile the Student class we are going to compile student.cpp and main.cpp separately, and then combine the results to create an executable file. Because this is a multi-step process, we are going to create a makefile to save us typing. Create a file called "makefile" and copy/paste the following into the file. Make sure that there is a TAB character in front of the g++ commands and NOT spaces.

    main.exe: main.o course.o student.o
    	g++ -o main.exe main.o course.o student.o
    main.o: main.cpp course.h student.h
    	g++ -Wall -c main.cpp
    course.o: course.cpp course.h student.h
    	g++ -Wall -c course.cpp
    student.o: student.cpp student.h
    	g++ -Wall -c student.cpp
    clean:
    	/bin/rm -f *.o *.exe
    

    Step 3: Now type in the command "make". You should see a sequence of four g++ commands that compile the code above to create main.exe. Now type "make" again to see what happens. The reason makefiles are so powerful is because they look at the time stamps of the input/output files to decide which commands to execute. This way, the make command only has to recompile the source files that have been modified and not every file. This is a huge time savings for large software projects.

    Step 4: Run your program by typing "./main.exe". You should see an error message printed out because the program is missing an input file. Create a file called "csce2004.txt" and copy/paste the following into the file. Now add several more fake student records in the same format.

    1234 Susan 3.9
    2345 John  3.2
    3456 Laura 3.8
    4567 Brian 3.5
    5678 David 3.1
    

    Run the program "./main.exe" and copy and paste the output below.

  7. Extending the Student Class
  8. Now that you have compiled and tested the Student class, you can see that the list of methods for this class is not very extensive. The goal of this section is to add several methods to the Student class. This will require changes to student.h (to define new methods), student.cpp (to implement new methods), and main.cpp (to test new methods). We will add and test new methods one at a time.

    Step 1: Edit student.h to add a new public method called "GetGPA" that has no parameters and returns the float value that is the student's GPA. Now edit student.cpp and type in the implementation of this method. Finally, edit main.cpp to call your "GetGPA" method several times and print out the results. To recompile, type "make".

    Copy and paste your implementation of GetGPA below.

    Step 2: Edit student.h to add a new public method called "SetGPA" that has one float parameter which is used to set student's GPA. Now edit student.cpp and type in the implementation of this method. This would be a good place to do some error checking to restrict GPAs to the range [0.0 .. 4.0]. If a user sets a value below that range set the GPA to 0.0, and if a user sets a value above that range set the GPA to 4.0. Finally, edit main.cpp to call your "SetGPA" method several times and print out the results. To recompile, type "make".

    Copy and paste your implementation of SetGPA below.

  9. Extending the Course Class
  10. Now that you have compiled and tested the Course class, you can see that the list of methods for this class is not very extensive. The goal of this section is to add several methods to the Course class. This will require changes to course.h (to define new methods), course.cpp (to implement new methods), and main.cpp (to test new methods). We will add and test new methods one at a time.

    Step 1: Edit course.h to add a new public method called "AverageGPA" that has no parameters and returns the average of all student GPAs in the course. Now edit course.cpp and type in the implementation of this method. Now you can see why we wrote the GetGPA method above. Finally, edit main.cpp to call your "AverageGPA" method and print out the results. To recompile, type "make".

    Copy and paste your implementation of AverageGPA below.

    Step 2: Edit course.h to add a new public method called "IncreaseGPA" that has one float parameter and adds this value to each of the student GPAs. Edit course.cpp and type in the implementation of this method. Once you think about this, you will see that you need to call both GetGPA and SetGPA to increase everyone's GPA. You do NOT need to worry about the GPA going above 4.0 because this is handled inside your SetGPA function. Finally, edit main.cpp to call your "IncreaseGPA" method and print out the results. To recompile, type "make".

    Copy and paste your implementation of IncreaseGPA below.

    Step 3: Compile and test your main.cpp program with several calls to AverageGPA and IncreaseGPA. For example, see what happens if you call AverageGPA before and after you add 0.5 to everyone's GPA using IncreaseGPA. You may get some unexpected results.

    Copy and paste your main.cpp program below.

    Run the program "./main.exe" and copy and paste the output below.

  11. Adding File Output to Student and Course Classes
  12. If you look closely at the Student and Course classes, you will see that they both have methods to read student data from an ASCII input file. In particular, we put the file open/close operations in the Course's "Read" method, and we let the Student class "Read" method do the actual file I/O to get the student's UAID, Name and GPA from the ifstream parameter. Your task in this section is to add "Write" methods to both Student and Course classes so you can save student grades in an ASCII file.

    Step 1: Edit student.h and student.cpp to add a new method called "Write" that outputs the UAID, Name and GPA in the same order used in the Read method. If you change the order of values then your program will die a horrible death if you try to read this file later. Compile and debug your program until this method is working.

    Copy and paste your Student Write method below.

    Step 2: Edit course.h and course.cpp to add a new method called "Write" that calls the Student Write method to output the UAID, Name and GPA for all students. Your code should look similar to the Read method. Compile and debug your program until this method is working.

    Copy and paste your Course Write method below.

    Step 3: Finally, edit your main.cpp program to call the Course Write method to save the modified student information in a file called "new2004.txt". With any luck, these student records will match what you printed out to the screen when you were debugging the AverageGPA and IncreaseGPA methods.

    Copy and paste the contents of new2004.txt below.

  13. Submit Work
  14. This lab assignment will be submitted electronically to the TAs once you fill in the fields below and click on the "submit" button. You do NOT need to print a copy of this document to hand in.

    Your UAID number:
    Your website PASSWORD: