This lab is designed to give you some exposure to using classes and defining classes when dynamically allocated memory is involved. In these cases, you have to be pretty careful with what goes on with pass-by-value, copy constuctors, const
-ness, and assignment!
To get you started as the user of a class or module involving dynamic memory, I'm giving you a class Grades
for storing and retrieving grade information on arbitrarily many assignments. Your interface to this module is grade.h:
/****************************************************
* grade.h --- Interface for the Grades module.
* Class Grades allows you to store grades and retrieve them by "index".
* The first grade you store has index 0, the second grade you store has index 1, etc.
****************************************************/
/** DECLARATION of class Node **/
class Node;
/** DEFINITION of class Grades **/
class Grades{
private:
// Disable pass-by-value and assignment!
Grades(const Grades&) { }
Grades& operator=(const Grades &G) { }
public:
Grades() {
head = tail = 0;
n = 0;
}
~Grades();
// adds a grade (positive grades only)
void addNextGrd(double score);
// retrieves grade from index - if a
// negative grade is returned, then
// there was no grade with that index!
double getGrd(int index) const;
// returns number of grades
int numGrd() const {
return n;
}
private:
Node *head, *tail;
int n;
};
The implementation is in a .cpp that I'm not going to let you see just yet. Instead, I will provide the object file necessary to compile your final executable. The file can be retrieved via: grade.o.
In the first part of the lab, you are going to use the provided Grades
module to write a program (in a file named part1.cpp) that tracks grades for two students. The program simply has a command prompt that allows the user to:
NG stu1score stu2score
AV
GD index
QT
Hint: Your compile command should look something like this:
g++ -o part1 part1.cpp grade.o
When you've got the program working, a typical run of it might look something like this:
Grades
object and return the average of the grades stored there.Grades
In the second part of the lab you are going to create a new class called Student
that stores the exam, homework and quiz grades for a student, as well as a name for the student. This class is used by the driver program driver.cpp:
/**************************************************
* driver.cpp - The program defined here is a simple
* program for tracking student grades for two students,
* Joe and Amy. The user has the following commands:
*
* NG <type> <student01's grade> <student02's grade>
* AV <type>
* TG
* QT
*
* Valid <type>s are "exam", "quiz", & "homework"
* NG - enters new <type> grades for student01 and student02
* AV - prints out the average for the provided <type>
* TG - prints the total grades for students, weighting exams 50%,
* quizes 30%, and homeworks 20%.
* QT - quits the program
**************************************************/
#include "student.h"
#include <string>
#include <iostream>
using namespace std;
// FUCNTION PROTOTYPES
// Prints out the total grade for student S, weighing
// exams 50%, quizzes 30% and homeworks 20%
double totgrd(const Student &S);
// MAIN FUNCTION
int main() {
Student S1("Joe"), S2("Amy");
string command;
while(cin >> command && command != "QT") {
if (command == "NG") {
string tp;
double g1, g2;
cin >> tp >> g1 >> g2;
S1.addNextGrd(g1,tp);
S2.addNextGrd(g2,tp);
}
else if (command == "AV") {
string tp;
cin >> tp;
cout << S1.name() << "'s " << tp << " average is " << S1.ave(tp) << endl;
cout << S2.name() << "'s " << tp << " average is " << S2.ave(tp) << endl;
}
else if (command == "TG") {
cout << S1.name() << "'s total grade is " << totgrd(S1) << endl;
cout << S2.name() << "'s total grade is " << totgrd(S2) << endl;
}
else
cout << "Unknown command!" << endl;
}
return 0;
}
// FUNCTION DEFINITIONS
double totgrd(const Student &S){
return 0.5*S.ave("exam") + 0.3*S.ave("quiz") + 0.2*S.ave("homework");
}
This part's program will look similar to the previous one. The commands NG and AV are still there, but each of them requires additional information from the user, namely the type of assignment: exam, quiz or homework. There is a new command called TG, which should print out the two student's total grade, weighting exams 50%, quizes 30%, and homeworks 20%. The following is a typical session with this program:
Your class should be defined in files names student.h
and student.cpp
, and it should be defined so that the driver program driver.cpp
compiles and runs properly. In particular, look at driver.cpp
to see what constructors and member functions are required.
You may not modify driver.cpp
. You may use the Grades
class from part 1 ... in fact you'd be crazy not to!
Hint: Your compile command should look something like this:
g++ -o part2 driver.cpp grade.o student.cpp
Now look at the implementation of the Grades module, grade.cpp:
#include "grade.h"
#include <cmath>
using namespace std;
/** DEFINITION OF CLASS NODE **/
class Node {
public:
double data;
Node *next;
Node(double val, Node* p) {
data = val; next = p;
}
};
/** DEFINITION OF Grade's MEMBERS **/
void Grades::addNextGrd(double val) {
n++;
if (!head)
head = tail = new Node(fabs(val),head);
else
tail = tail->next = new Node(fabs(val),0);
}
double Grades::getGrd(int index) const {
Node *p = head;
for(int i = 0; p != 0 && i != index; i++)
p = p->next;
if (p) return p->data;
else return -1;
}
Grades::~Grades() {
while(head != 0) {
Node *p = head;
head = head->next;
delete p;
}
}
Try to understand how it works. In particular, how does this implementation make sure that any memory that's allocated with new
is deallocated with delete
, and no object is deallocated with delete
unless it's certain that no attempt to use the object will ever be made again. Notice how it simply bypassed the pitfalls presented by pass-by-value and assignment by disallowing them! Pretty sneaky, eh? In driver.cpp
, the function totgrd
uses pass-by-reference rather than pass-by-value. Turn in the answers to these questions with the lab as well (in part3.txt):
A natural final step in this process would be to create a class called Section
to store Student
objects for each of the students in a particular section. You'd probably want to store the section number as well. What member functions would you want to be available to the user of such a class? What constructors? Would a destructor be needed? Would pass-by-value or assignment be a problem for this class?
Submit all source code necessary to complete parts 1 and 2 and your answers to part 3 (i.e. part1.cpp, student.h, student.cpp & part3.txt) to the submisison website: submit.cs.usna.edu
~/bin/submit -c=SI221 -p=Lab04 part1.cpp student.h student.cpp part3.txt
Do NOT submit any .o or executable files.