CPSC170
Fundamentals of Computer Science II

Lab 12

Classes

Separation of Interface and Implementation

In the previous lab, you created a struct called Student. It had both data and function members. It is good programming practice to separate the interface of a struct/class from its implementation. This promotes code reusability and maintenance. We will define the Student struct over two files, student.h and student.cc. student.h will contain the definition of the struct along with data members and function headers followed by a semicolon. Your student.h file should look similar to the following.


#pragma once

const int MAX_NAME_SIZE = 50

 // The name of this struct is Student. Note the struct keyword.
 struct Student {

 // The first name is represented by a sequence of characters.
 char firstName[MAX_NAME_SIZE];
 // The second name is represented by a sequence of characters.
 char lastName[MAX_NAME_SIZE];
 // The students age is represented by an unsigned integer.
 unsigned age;

 // creates a default student.
 Student();
	
 //PRE: name is a character array of length at most MAX_NAME_SIZE and contains
 //     the null character '\0'.
 //POST: Starting from the first position, all the characters in name up till
 //      and including the null character written to lastName.
 void setLastName(const char name[]);

 //PRE: name is a character array of length at most MAX_NAME_SIZE and contains
 //     the null character '\0'.
 //POST: Starting from the first position, all the characters in name up till
 //      and including the null character written to firstName.
 void setFirstName(const char name[]);

 // print the student's data to the standard output.
 void print();
};


Don't forget to add your header guards (It prevents your header file from being included more than once in a file). As you can see sudent.h only lacks function definitions. The function definitions will go into student.cc. This file should include student.h along with any other headers needed by your function implementations. In order to implement a function in the struct we use the scope resolution operator (::). This operator along with the name of the struct is used to tell the compiler that we are defining members of a struct. Here's what student.cc might look like.

#include <iostream>
#include "student.h"


//creates a default student.
Student::Student() {
  /*code*/
}

//PRE: name is a character array of length at most MAX_NAME_SIZE and contains
//     the null character '\0'.
//POST: Starting from the first position, all the characters in name up till
//      and including the null character written to lastName.
void Student::setLastName(const char name[]) {
  /*code*/
}

//PRE: name is a character array of length at most MAX_NAME_SIZE and contains
//     the null character '\0'.
//POST: Starting from the first position, all the characters in name up till
//      and including the null character written to firstName.
void Student::setFirstName(const char name[]) {
  /*code*/
 }

//Prints the student's data to the standard output.
void Student::print() {
  /*code*/
}

The line of code void Student::setLastName(const char name[]) {/*code*/} tells the compiler that the function setLastName is a member of Student. It is just like the namespace std and the standard output device cout. cout is a member of std so we access cout with the statement std::cout.

You should be able to compile student.cc. Now you can use your Student struct by including its header in any file that uses Student. In the current directory, make a file driver.cc. It should include student.h and have a main function where you use the struct Student. Use a make file to compile and link the files required to run the code in driver.cc. Use this make file for the rest of the lab.

Classes

We will create a class called Section. It's meant to hold the records of students in a section of a class. We will use the struct Student. Section will have two private data members called students and size. students is an array of 100 Students. size is the number of students currently enrolled. Below is the basic structure of the class. We will increase its functionality over the course of this lab by adding various methods.


class Section {
  private:
    int Section_size = 0;
    Student students[MAX_SEC_SIZE];

  public:
    //Pre: the Section_size is less than MAX_SEC_SIZE
    //Post: student has been added to the Section.
    //      The Section_size is increased by 1.
    void addStudent(const Student& student) {};
};
	

As you can see the syntax for declaring a class is identical to that of a struct. In fact, the only syntactic difference is the use of the keyword class rather than struct. The keywords private and public are called access modifiers. Although we didn't use them in the previous lab, they can be used with structs also. As the name suggests access modifiers regulate how members of a class are accessed. private members can only be accessed within the class.

Create a Section object, now try to print Section_size. You will get a compile-time error. This is because Section_size is a private member. If you replace private with public, your code will compile. This is because public members can be accessed outside of the class while private members can't be accessed outside of the class.

Task 1: Flesh out Section with other public functions. I have provided a header for the public function addStudent(const Student& student). Its job is to copy the given Student struct into a Section object's students array. Its parameter student is passed by const reference. This achieves two goals, it prevents a new copy of student being made and it prevents addStudent() from altering student. Basically, addStudent() is only allowed to read from student.

Add the following functions with appropriate Pre/Post comments. The comments following //Pre: and //Post: are informal descriptions of each function. They shouldn't be part of your code. Notice that some of these function headers end with the keyword const. This ensures that the function doesn't alter the internal state of the class. If you try to write to any of the data members, you'll get a compile time error.


 //Pre:
 //Post:
 // removes the student at position i from the students array. i is between 0 and
 //  Section_size-1.
 void removeStudent(int i)

 //Pre:
 //Post:
 // empties the Section.
 void emptySection()

 //Pre:
 //Post:
 // returns the size of the Section.
 int getSectionSize() const;

 //Pre:
 //Post:
 // copies the student at position i into student.
 void copyStudent(int i, Student& student) const;
 
 //Pre:
 //Post:
 // returns the student at position i.
 Student getStudent(int i) const;

 //Pre:
 //Post:
 // Searches for a student with the given first and last names.
 // If the student is found, found is set to true and postion
 // is set to the position of the student in the array students.
 void find_student(char first_name[], char last_name[],
		           int& position, bool& found) const;

 //Pre:
 //Post:
 // prints the entire Section roster. Your implementation should be recursive.
 void print_Section_roster() const;

To implement a recursive print function. You'll need a recursive helper function that takes an integer. Should this helper function be public or private?

Task 2: Write a function (create helper functions to simplify the task) that reads in the information of students stored in a file. Assume the file is formatted a follows. The first line of the file contains the number of students in the Section. Each following line contains a student's information in the order first name, last name, age and, ID. A sample file can be found here. Make various test cases to test your function.