Description
In this project, you will build a program to manage student grades. A student will be defined as a class containing three member variables: a first name string, a last name string, and an array of 5 double scores for assignments.
You MUST create a class named Student, with the class declaration in the header file Student.h, and the implementation of the member functions in Student.cpp. In Student.h, create a named constant for the number of assignments (5), and use that to control your loops, etc. Your goal is to be able to take your program, change that one named constant, and be able to process an input file with 6 scores per student. In the description below, I’m going to assume that this constant is named MAX_ASSIGNMENTS.
Where should you declare your named constant? In future courses, you’ll learn how to place them inside of the class. For now, put it in the Student.h header file, BEFORE the class itself. This will make it available inside Student.h, inside Student.cpp, and inside your Project3.cpp file containing main()(since the .cpp files include the Student.h file).
Your Student class should have the following:
A default constructor which will initialize the names to empty strings, and every element of the array of assignment scores to 0.
A member function, readFromFile(), that accepts one parameter (an input file stream by reference), reads the data for one student from a text file, and stores the data in its member variables. It will return true if it was able to read the data, false otherwise.
A member function setFirst() that accepts one parameter (a student’s first name) and stores it in the appropriate member variable.
A member function setLast() that accepts one parameter (a student’s last name) and stores it in the appropriate member variable. Note that you can write the constructor using calls to setFirst() and setLast() if you wish.
A member function, getFirst(), which returns the first name. Note that this and the following member function can be written inline.
A member function, getLast(), which returns the last name.
A member function, setScore(), that accepts two parameters (an integer assignment number from 1 through MAX_ASSIGNMENTS, and a double score from 0.0 through 100.0) and stores the score in the appropriate element of the private score array.
A member function, getScore(), which accepts one parameter (an integer assignment number from 1 through MAX_ASSIGNMENTS) and returns the double score associated with that assignment number.
A member function, getAverage(), which returns the average of the student’s scores. Always divide by the maximum number of scores, even if some scores are 0 (hint: use the constant described above).
A member function, display(), which will output all of a student’s data, formatted neatly on one line. Use setw() to format it neatly into columns.
Note that the setScore() and getScore() member functions use assignment numbers starting at 1. However, the array in which they must maintain those values has indices that start at 0. These functions must translate the parameter from an “outside view”, where assignment numbers start at 1, to an “internal view”, where assignment #1 must be stored in the array at index 0, assignment #2 is stored in index 1, etc.
There are no restrictions on the names, but there are on the assignment numbers and student scores. Inside the setScore() member function, if the assignment number or score is invalid (assignment number outside the range 1 through MAX_ASSIGNMENTS, or score outside the range 0 through 100.0), the function should return without taking any action. Otherwise, it should store the score in the appropriate index. The getScore() member function MUST return something, so if the assignment number is invalid, return a score of 0.0. Otherwise, return the score from the proper element of the array (if they ask for the score on assignment 1, you must return what is stored in the array at index 0, etc).
Here is a table summarizing the member functions of the Student class:
Return Type
Function Name
Parameter(s)
(none)
Student()
(none)
bool
readFromFile()
ifstream &
void
setFirst()
string
void
setLast()
string
string
getFirst()
(none)
string
getLast()
(none)
void
setScore()
int, double
double
getScore()
int
double
getAverage()
(none)
void
display()
(none)
Inside of the Project3.cpp file, you should break down the tasks required to finish the assignment into logical functions. Writing it as one, large, function is not good coding style, and will not get you the maximum points. You will need to do the following:
Create an array of Student objects, with a maximum size of 100 (hint: define a constant for this).
Open the file scores.txt. If the file does not exist, display an error message and exit.
If the file opened properly, read the data into the array of Student objects. Each line consists of a student name (first then last), followed by five double values representing the scores (more on this below). Make sure that you stop reading when either the array is full, or there are no students left to read. This is a great candidate for a function ( see readData() function from the Chapter 8 slides as a guide).
Display a formatted table to cout (see example below), including the average for each student. After the table, display an overall class average. (Another good place for a function.)
We already know about the basic while loop conditions of reading until we either fill the array or run out of things to read. For reading data for a single student in your readFromFile() member function, you can assume if you are able to read a first name, then you are guaranteed to be able to read the rest of the data for this student. There will not be partial data in the file. When you need to read the scores for a given student, make sure to use a loop, and use the named constant for the maximum number of assignments (5).
if ( file first last )
{
// Use a loop to read all of the scores for this
// student. Store them in the array member variable,
// at the correct index.
return true;
}
return false;
Here is an example of some input data in scores.txt (this is the first two students):
John Smith 87 97 85 67 74
Lisa Able 60 70 80 90 100
The above input might produce output something like:
Name A1 A2 A3 A4 A5 Avg
—- —– —– —– —– —– —–
Lisa Able 60.0 70.0 80.0 90.0 100.0 80.0
John Smith 87.0 97.0 85.0 67.0 74.0 82.0
Overall class average: 81.00
Tiered grading:
60% Open the input file. If it cannot be opened, terminate the program with an appropriate error message. If it is opened, read the data into the array of objects. You must store the data in an array of objects, and DO NOT use global variables. Start using functions to break down main() into smaller pieces (see the additional 20% for good programming below).
70% Display the student names and scores that you have read in, formatted and aligned neatly in columns. You should first print an appropriate heading also aligned.
80% Compute and display the average for each student, and at the bottom, the overall class average.
Up to 20% will be awarded for good programming practices, broken down as follows:
1% Use of named constants.
1% Meaningful identifiers for named constants and variables.
6% Use of functions to break down the program into manageable pieces. You should create at least TWO functions besides main() and the class functions.
5% Proper formatting, indenting, and use of blank lines.
6% Meaningful comments. Add a block comment at the start of the file, and comment each section of code. Add a block comment for each function, and each member function, describing its purpose.
1% No compiler warnings. Make sure that you specifically BUILD your project, instead of choosing to run with F5, and answering yes. You will not see any warnings if you build by running. If you have trouble with any, let me know and I will help you clean them up.
Remember to use the programs in the book and the example in the Coding Guidelines for samples of properly indented code. Remember that you can highlight an entire block of text (using the mouse or keyboard) and then press the Tab key to indent it another level, or shift-Tab to unindent by one level.
Make sure that your program compiles under Visual Studio (full version or Express). With the tiered grading system, most of you should have a good idea of approximately how many points you are going to receive. If you have been programming on a Mac or under Unix, test your program with Visual Studio before submitting it.
When you are done, place your THREE source code files (two .cpp and one .h), in the Project 3 Dropbox.
Notes:
The zip file contains 5 files: this document, input scores (scores.txt) and sample output (Sample-output.txt). There is also sample input and output to test if your code works with 6 scores properly; the files are named scores6.txt and Sample-output-6.txt. You do not have to produce an output file as part of your program. They are just included here as a sample of how the output on the screen could appear.
Your program does not have to work with the scores6.txt file, but this is a great test of your program. If you can change the name of the file you open, change your MAX_ASSIGNMENTS constant from 5 to 6, rebuild, and the output looks correct, you’ve probably done a good job.
The sample input and output is meant to demonstrate everything that your program should be able to do. Your output does not have to be identical to that provided in the sample (feel free to format it differently), but it should be laid out in a similar fashion. Note: your output does NOT have to be in alphabetical order as it appears in the examples.
When you want to print headings (the A1 A2, etc), think about what happens if you put this entire string in double quotes: “A1 A2 A3 A4 A5”? What happens if you need to update your program to work with 6 scores? Instead of putting all the score labels inside quote marks, use a for loop to produce the headings! Any time you find yourself typing the value 4 or 5, stop and think whether a for loop would be a better solution (it probably is).
How do you output both the first and last names into a single field of a given width? Let’s assume that we want both names together in a field of width 30. Then we can code:
cout << left << setw( 30 ) << first + " " + last << right; This means that if first contains the first name we want to print, and last contains the last name, we put them together using +, into one string (with a blank space in between), then output that string in the width that we set. The use of left and right causes the name to be left justified, but then sets the output stream back to right justification for the upcoming numeric values. One final note: writing code to simply produce output unique to this sample data is NOT a valid approach. For example, the following code is unacceptable: cout << "Lisa Able 60 70 80 90 100 "; avg = 80; cout << avg << endl;