7.6. Case Study: Class GradeBook
Using an Array to Store Grades
This section further evolves class
GradeBook, introduced in Chapter
3 and expanded in Chapters
4–6. Recall that this class represents a grade book
used by a professor to store and analyze student grades. Previous versions of
the class process grades entered by the user, but do not maintain the individual
grade values in the class's data members. Thus, repeat calculations require the
user to reenter the grades. One way to solve this problem would be to store each
grade entered in an individual data member of the class. For example, we could
create data members grade1, grade2, . . ., grade10 in
class GradeBook to store 10 student grades.
However, the code to total the grades and determine the class average would be
cumbersome. In this section, we solve this problem by storing grades in an
array.
Storing Student Grades in an Array
in Class GradeBook
The version of class GradeBook
(Figs. 7.16–7.17) presented here uses an array of integers to store the
grades of several students on a single exam. This eliminates the need to
repeatedly input the same set of grades. Array grades is declared as a
data member in line 29 of Fig. 7.16—therefore, each
GradeBook object maintains its own set of grades.
Fig. 7.16. Definition of class GradeBook using
an array to store test grades.
1 // Fig. 7.16: GradeBook.h
2 // Definition of class GradeBook that uses an array to store test grades.
3 // Member functions are defined in GradeBook.cpp
4
5 #include <string> // program uses C++ Standard Library string class
6 using std::string;
7
8 // GradeBook class definition
9 class GradeBook
10 {
11 public:
12 // constant -- number of students who took the test
13 const static int students = 10; // note public data
14
15 // constructor initializes course name and array of grades
16 GradeBook( string, const int [] );
17
18 void setCourseName( string ); // function to set the course name
19 string getCourseName(); // function to retrieve the course name
20 void displayMessage(); // display a welcome message
21 void processGrades(); // perform various operations on the grade data
22 int getMinimum(); // find the minimum grade for the test
23 int getMaximum(); // find the maximum grade for the test
24 double getAverage(); // determine the average grade for the test
25 void outputBarChart(); // output bar chart of grade distribution
26 void outputGrades(); // output the contents of the grades array
27 private:
28 string courseName; // course name for this grade book
29 int grades[ students ]; // array of student grades
30 }; // end class GradeBook
|
Note that the size of the array in line 29 of Fig. 7.16 is specified by public
const static data member students (declared in line 13). This data
member is public so that it is accessible to the
clients of the class. 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—all
GradeBook objects store grades for the same number of students. Recall
from Section
3.6 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 (instance) 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 is 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 binary scope resolution
operator (::) and the name of the data member. You'll learn more about
static data members in Chapter
10.
The class's constructor (declared in line 16 of Fig. 7.16 and defined
in lines 17–24 of Fig.
7.17) has two parameters—the course name and
an array of grades. When a program creates a GradeBook object (e.g.,
line 13 of fig07_18.cpp), the program passes an existing int array to the constructor, which copies the array's values
into the data member grades (lines 22–23 of Fig. 7.17).
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
17, File Processing). In our test program, we simply
initialize an array with a set of grade values (Fig. 7.18, lines
10–11). 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.
Fig. 7.17. GradeBook class member functions manipulating an array
of grades.
1 // Fig. 7.17: GradeBook.cpp
2 // Member-function definitions for class GradeBook that
3 // uses an array to store test grades.
4 #include <iostream>
5 using std::cout;
6 using std::cin;
7 using std::endl;
8 using std::fixed;
9
10 #include <iomanip>
11 using std::setprecision;
12 using std::setw;
13
14 #include "GradeBook.h" // GradeBook class definition
15
16 // constructor initializes courseName and grades array
17 GradeBook::GradeBook( string name, const int gradesArray[] )
18 {
19 setCourseName( name ); // initialize courseName
20
21 // copy grades from gradesArray to grades data member
22 for ( int grade = 0 ; grade < students; grade++ )
23 grades[ grade ] = gradesArray[ grade ];
24 } // end GradeBook constructor
25
26 // function to set the course name
27 void GradeBook::setCourseName( string name )
28 {
29 courseName = name; // store the course name
30 } // end function setCourseName
31
32 // function to retrieve the course name
33 string GradeBook::getCourseName()
34 {
35 return courseName;
36 } // end function getCourseName
37
38 // display a welcome message to the GradeBook user
39 void GradeBook::displayMessage()
40 {
41 // this statement calls getCourseName to get the
42 // name of the course this GradeBook represents
43 cout << "Welcome to the grade book for\n" << getCourseName() << "!"
44 << endl;
45 } // end function displayMessage
46
47 // perform various operations on the data
48 void GradeBook::processGrades()
49 {
50 // output grades array
51 outputGrades();
52
53 // call function getAverage to calculate the average grade
54 cout << "\nClass average is " << setprecision( 2 ) << fixed <<
55 getAverage() << endl;
56
57 // call functions getMinimum and getMaximum
58 cout << "Lowest grade is " << getMinimum() << "\nHighest grade is "
59 << getMaximum() << endl;
60
61 // call function outputBarChart to print grade distribution chart
62 outputBarChart();
63 } // end function processGrades
64
65 // find minimum grade
66 int GradeBook::getMinimum()
67 {
68 int lowGrade = 100 ; // assume lowest grade is 100
69
70 // loop through grades array
71 for ( int grade = 0 ; grade < students; grade++ )
72 {
73 // if current grade lower than lowGrade, assign it to lowGrade
74 if ( grades[ grade ] < lowGrade )
75 lowGrade = grades[ grade ]; // new lowest grade
76 } // end for
77
78 return lowGrade; // return lowest grade
79 } // end function getMinimum
80
81 // find maximum grade
82 int GradeBook::getMaximum()
83 {
84 int highGrade = 0; // assume highest grade is 0
85
86 // loop through grades array
87 for ( int grade = 0 ; grade < students; grade++ )
88 {
89 // if current grade higher than highGrade, assign it to highGrade
90 if ( grades[ grade ] > highGrade )
91 highGrade = grades[ grade ]; // new highest grade
92 } // end for
93
94 return highGrade; // return highest grade
95 } // end function getMaximum
96
97 // determine average grade for test
98 double GradeBook::getAverage()
99 {
100 int total = 0; // initialize total
101
102 // sum grades in array
103 for ( int grade = 0; grade < students; grade++ )
104 total += grades[ grade ];
105
106 // return average of grades
107 return static_cast< double >( total ) / students;
108 } // end function getAverage
109
110 // output bar chart displaying grade distribution
111 void GradeBook::outputBarChart()
112 {
113 cout << "\nGrade distribution:" << endl;
114
115 // stores frequency of grades in each range of 10 grades
116 const int frequencySize = 11;
117 int frequency[ frequencySize ] = {}; // initialize elements to 0
118
119 // for each grade, increment the appropriate frequency
120 for ( int grade = 0; grade < students; grade++ )
121 frequency[ grades[ grade ] / 10 ]++;
122
123 // for each grade frequency, print bar in chart
124 for ( int count = 0; count < frequencySize; count++ )
125 {
126 // output bar labels ("0-9:", ..., "90-99:", "100:" )
127 if ( count == 0 )
128 cout << " 0-9: ";
129 else if ( count == 10 )
130 cout << " 100: ";
131 else
132 cout << count * 10 << "-" << ( count * 10 ) + 9 << ": ";
133
134 // print bar of asterisks
135 for ( int stars = 0; stars < frequency[ count ]; stars++ )
136 cout << '*';
137
138 cout << endl; // start a new line of output
139 } // end outer for
140 } // end function outputBarChart
141
142 // output the contents of the grades array
143 void GradeBook::outputGrades()
144 {
145 cout << "\nThe grades are:\n\n";
146
147 // output each student's grade
148 for ( int student = 0; student < students; student++ )
149 cout << "Student " << setw( 2 ) << student + 1 << ": " << setw( 3 )
150 << grades[ student ] << endl;
151 } // end function outputGrades
|
Member function processGrades (declared in line 21 of
Fig. 7.16 and defined in lines 48–63 of Fig. 7.17) contains a series of member function calls that
output a report summarizing the grades. Line 51 calls member function
outputGrades to print the contents of the array grades. Lines
148–150 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 149–150 output student + 1 as the
student number to produce grade labels "Student 1: ", "Student 2:
", and so on.
Member function processGrades next calls member
function getAverage (lines 54–55) to obtain the
average of the grades in the array. Member function getAverage (declared in line 24 of Fig. 7.16 and
defined in lines 98–108 of Fig. 7.17) uses a for statement to total the values in array grades before calculating the average. Note that the averaging
calculation in line 107 uses const static data member
students to determine the number of grades
being averaged.
Lines 58–59 in member function 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 68). Then, we compare each of the elements in the array to
the lowest grade, looking for smaller values. Lines 71–76 in member function
getMinimum loop through the array, and lines 74–75
compare each grade to lowGrade. If a grade is less than
lowGrade, lowGrade is set to that grade. When line 78
executes, lowGrade contains the lowest grade in the array. Member
function getMaximum (lines 82–95) works similarly to member function
getMinimum.
Finally, line 62 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.9. 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 this example, lines 120–121 use a
technique similar to that in Fig.
7.10 and Fig.
7.11 to calculate the frequency of grades in each
category. Line 117 declares and creates array frequency of 11
ints to store the frequency of grades in
each grade category. For each grade in array grades, lines 120–121 increment the appropriate element of
the frequency array. To determine which
element to increment, line 121 divides the current grade by 10 using
integer division. For example, if grade is 85, line 121
increments frequency[ 8 ] to update the count
of grades in the range 80–89. Lines 124–139 next print the bar chart (see Fig. 7.18) based on the
values in array frequency. Like lines 29–30 of Fig.
7.9, lines 135–136 of Fig. 7.17 use a value in array
frequency to determine the number of asterisks
to display in each bar.
Fig. 7.18. Creates a GradeBook object using an array of grades, then invokes member
function processGrades to analyze them.
1 // Fig. 7.18: fig07_18.cpp
2 // Creates GradeBook object using an array of grades.
3
4 #include "GradeBook.h" // GradeBook class definition
5
6 // function main begins program execution
7 int main()
8 {
9 // array of student grades
10 int gradesArray[ GradeBook::students ] =
11 { 87, 68, 94, 100, 83, 78, 85, 91, 76, 87 };
12
13 GradeBook myGradeBook(
14 "CS101 Introduction to C++ Programming", gradesArray );
15 myGradeBook.displayMessage();
16 myGradeBook.processGrades();
17 return 0;
18 } // end main
|
Welcome to the grade book for
CS101 Introduction to C++ Programming!
The grades are:
Student 1: 87
Student 2: 68
Student 3: 94
Student 4: 100
Student 5: 83
Student 6: 78
Student 7: 85
Student 8: 91
Student 9: 76
Student 10: 87
Class average is 84.90
Lowest grade is 68
Highest grade is 100
Grade distribution:
0-9:
10-19:
20-29:
30-39:
40-49:
50-59:
60-69: *
70-79: **
80-89: ****
90-99: **
100: *
|
Testing Class GradeBook
The program of Fig. 7.18 creates an object of class
GradeBook (Figs. 7.16–7.17) using the int array
gradesArray (declared and initialized in
lines 10–11). Note that we use the binary scope resolution operator
(::) in the expression
"GradeBook::students" (line 10) to access class GradeBook's
static constant students. We use
this constant here to create an array that is the same size as array
grades stored as a data member in class
GradeBook. Lines 13–14 pass a course name and
gradesArray to the GradeBook
constructor. Line 15 displays a welcome message, and line 16 invokes the
GradeBook object's processGrades member function. The output
reveals the summary of the 10 grades in myGradeBook.