GradeBook
Using an array
to Store GradesWe now present the first part of our case study on developing a GradeBook
class that instructors can use to maintain students’ grades on an exam and display a grade report that includes the grades, class average, lowest grade, highest grade and a grade distribution bar chart. The version of class GradeBook
presented in this section stores the grades for one exam in a one-dimensional array. In Section 7.9, we present a version of class GradeBook
that uses a two-dimensional array to store students’ grades for several exams.
array
in Class GradeBook
Figure 7.12 shows the output that summarizes the 10 grades we store in an object of class GradeBook
(Fig. 7.13), which uses an array
of integers to store the grades of 10 students for a single exam. The array
grades
is declared as a data member in line 142 of Fig. 7.13—therefore, each GradeBook
object maintains its own set of grades.
The size of the array
in line 142 of Fig. 7.13 is specified by public
static
const
data member students
(declared in line 12), which is public
so that it’s accessible to the class’s clients. We’ll soon see an example of a client program using this constant. Declaring students
with the const
qualifier indicates that this data member is constant—its value cannot be changed after being initialized. Keyword static
in this variable declaration indicates that the data member is shared by all objects of the class—so in this particular implementation of class GradeBook
, all GradeBook
objects store grades for the same number of students. Recall from Section 3.3 that when each object of a class maintains its own copy of an attribute, the variable that represents the attribute is known as a data member—each object of the class has a separate copy of the variable in memory. There are variables for which each object of a class does not have a separate copy. That’s the case with static data members
, which are also known as class variables. When objects of a class containing static
data members are created, all the objects share one copy of the class’s static
data members. A static
data member can be accessed within the class definition and the member-function definitions like any other data member. As you’ll soon see, a public
static
data member can also be accessed outside of the class, even when no objects of the class exist, using the class name followed by the scope resolution operator (::
) and the name of the data member. You’ll learn more about static
data members in Chapter 9.
The class’s constructor (lines 15–18) has two parameters—the course name and a reference to an array
of grades. When a program creates a GradeBook
object (e.g., line 13 of Fig. 7.14), the program passes an existing int
array
to the constructor, which copies the array
’s values into the data member grades
(line 17 of Fig. 7.13). The grade values in the passed array
could have been input from a user or read from a file on disk (as we discuss in Chapter 14, File Processing). In our test program, we simply initialize an array
with a set of grade values (Fig. 7.14, lines 9–10). Once the grades are stored in data member grades
of class GradeBook
, all the class’s member functions can access the grades
array
as needed to perform various calculations. Note that the constructor receives both the string
and the array
by reference—this is more efficient than receiving copies of the original string
and array
. The constructor does not need to modify either the original string
or array
, so we also declared each parameter as const
to ensure that the constructor does not accidentally modify the original data in the caller. We also declared function setCourseName
to receives its string
argument by reference.
processGrades
Member function processGrades
(lines 38–50 of Fig. 7.13) contains a series of member function calls that output a report summarizing the grades. Line 39 calls member function outputGrades
to print the contents of the array
grades
. Lines 135–138 in member function outputGrades
use a for
statement to output each student’s grade. Although array
indices start at 0, a professor would typically number students starting at 1. Thus, lines 136–137 output student + 1
as the student number to produce grade labels "Student 1: "
, "Student 2: "
, and so on.
getAverage
Member function processGrades
next calls member function getAverage
(line 43) to obtain the average of the grades. Member function getAverage
(lines 83–93) totals the values in array
grades
before calculating the average. The averaging calculation in line 92 uses grades.size()
to determine the number of grades being averaged.
getMinimum
and getMaximum
Lines 46–47 in processGrades
call member functions getMinimum
and getMaximum
to determine the lowest and highest grades of any student on the exam, respectively. Let’s examine how member function getMinimum
finds the lowest grade. Because the highest grade allowed is 100, we begin by assuming that 100 is the lowest grade (line 54). Then, we compare each of the elements in the array
to the lowest grade, looking for smaller values. Lines 57–62 in member function getMinimum
loop through the array
, and line 59 compares each grade to lowGrade
. If a grade is less than lowGrade
, lowGrade
is set to that grade. When line 64 executes, lowGrade
contains the lowest grade in the array
. Member function getMaximum
(lines 68–80) works similarly to member function getMinimum
.
outputBarChart
Finally, line 49 in member function processGrades
calls member function outputBarChart
to print a distribution chart of the grade data using a technique similar to that in Fig. 7.7. In that example, we manually calculated the number of grades in each category (i.e., 0–9, 10–19, …, 90–99 and 100) by simply looking at a set of grades. In Fig. 7.13, lines 104–106 use a technique similar to that in Fig. 7.8 and Fig. 7.9 to calculate the frequency of grades in each category. Line 100 declares and creates array
frequency
of 11 unsigned
int
s to store the frequency of grades in each grade category. For each grade
in array
grades
, lines 104–106 increment the appropriate element of the frequency
array
. To determine which element to increment, line 105 divides the current grade
by 10 using integer division. For example, if grade
is 85
, line 105 increments frequency[8]
to update the count of grades in the range 80–89. Lines 109–127 next print the bar chart (see Fig. 7.12) based on the values in array frequency
. Like lines 28–30 of Fig. 7.7, lines 122–124 of Fig. 7.13 use a value in array frequency
to determine the number of asterisks to display in each bar.
GradeBook
The program of Fig. 7.14 creates an object of class GradeBook
using the int
array
grades
(declared and initialized in lines 9–10). The scope resolution operator (::
) is used in the expression GradeBook::students
(line 9) to access class GradeBook
’s static
constant students
. We use this constant here to create an array
that’s the same size as the array
stored as a data member in class GradeBook
. Line 11 declares a string
representing the course name. Line 13 passes the course name and the array
of grades to the GradeBook
constructor. Line 14 displays a welcome message, and line 15 invokes the GradeBook
object’s processGrades
member function.