Please send questions to st10@humboldt.edu .
/*--------------------------------------------------------
 Implementation file for class Student WITH 
    explicitly-defined destructor, copy constructor, and 
    overloaded assignment operator.
 
 created by: Sharon Tuttle
 last modified: 12-03-03 - (based on posted Student2.cpp from
                           Week 14-2 lecture)
                12-11-03 - now #includes Student.h again
                           (instead of Student2.h),
                           and includes overloaded == operator
 ---------------------------------------------------------*/
#include <iostream>
#include "Student.h"
using namespace std;

//-----
// implementation of constructors
//-----

Student::Student (string gvn_lastName, string gvn_firstName,
		  int gvn_numGrades)
{
    lastName = gvn_lastName;
    firstName = gvn_firstName;
    numGrades = gvn_numGrades;

    gradesArray = new double[numGrades];
}
        
Student::Student ()
{
    lastName = "";
    firstName = "";
    numGrades = 0;
    gradesArray = NULL;
}

//-----
// implementation of copy constructor
//-----

Student::Student (const Student& studentObject)
{
    lastName = studentObject.lastName;
    firstName = studentObject.firstName;
    numGrades = studentObject.numGrades;

    if (numGrades > 0)
    {
        gradesArray = new double[numGrades];

        for (int i=0; i < numGrades; i++)
        {
            gradesArray[i] = studentObject.gradesArray[i];
        }
    }
    else
    {
        gradesArray = NULL;
    }    
}

//-----
// implementation of destructor
//-----

Student::~Student()
{
    delete [ ] gradesArray;
}

//-----
// implementation of accessor functions
//-----
string Student::get_lastName() const
{
    return lastName;
}

string Student::get_firstName() const
{
    return firstName;
}

int Student::get_numGrades() const
{
    return numGrades;
}

// returns the ith grade for this student
//    (return -1 if gradesArray NULL or
//    i is out-of-bounds)
double Student::get_grade(int i) const
{
    // make sure it is reasonable to even attempt to
    //    grab this grade... return -1 if it ISN'T
    if ((gradesArray == NULL) ||
        ((i < 0) || (i >= numGrades)))
    {
        return -1;
    }

    // IF reach here --- should be OK to at least
    //    TRY to grab ith grade.
    // (IF user hasn't set yet? well... OK, they're stuck
    //    then...)
    else
    {
        return gradesArray[i];
    }
}

//-----
// implementation of mutator functions
//-----
void Student::set_lastName(string new_lastName)
{
    lastName = new_lastName;
}

void Student::set_firstName(string new_firstName)
{
    firstName = new_firstName;
}

// note that this also dynamically allocates
//    a gradesArray of this size...
void Student::set_numGrades(int new_numGrades)
{
    numGrades = new_numGrades;

    // draconian as specified: if were grades before,
    //    they are now NUKED...
    if (gradesArray != NULL)
    {
        delete [ ] gradesArray;
    }

    // in ALL cases: allocate a new gradesArray of this
    //    new size
    gradesArray = new double[numGrades];
}

// set the ith grade in gradesArray to newGrade
void Student::set_grade(int i, double newGrade)
{
    if ((i < 0) || (i >= numGrades))
    {
        cout << "Student::set_grade: index " << i 
             << " is out of bounds!" << endl;
    }
    else
    {
        gradesArray[i] = newGrade;
    }
}

//-----
// implementation of overloaded operators
//-----
void Student::operator =(const Student& rightHandStudent)
{
    lastName = rightHandStudent.lastName;
    firstName = rightHandStudent.firstName;
    numGrades = rightHandStudent.numGrades;

    if (numGrades > 0)
    {
        gradesArray = new double[numGrades];

        for (int i=0; i < numGrades; i++)
        {
            gradesArray[i] = rightHandStudent.gradesArray[i];
        }
    }
    else
    {
        gradesArray = NULL;
    }    
}   

bool Student::operator == (const Student& rhStud) const
{
    // check if easy-to-compare fields are equal, first
    if ((lastName != rhStud.lastName)
        || (firstName != rhStud.firstName)
        || (numGrades != rhStud.numGrades))
    {
        return false;
    }

    // IF get here --- "easy-to-compare" fields had to be
    //    equal. All that leaves are the gradesArrays;
    //    are they equivalent?
    for (int i=0; i < numGrades; i++)
    {
        // if find ANY grade that doesn't correspond,
        //    these Students are not equivalent
        // (note that we're considering 2 double values
        //    as equivalent if they are "close enough")
        if (! (abs(gradesArray[i] - rhStud.gradesArray[i]) < .00001))
        {
            return false;    
        }
    }

    // if get here? all grades were equal! (or close enough...)
    return true;
}

//-----
// implementation of other member functions
//-----

//----
// Contract: avgGrade : void -> double
// Purpose: returns the average of the grades
//          in calling Student's gradesArray;
//          returns -1 if gradesArray == NULL.
//
// Examples: for Student emptyStudent(); :
//              emptyStudent.avgGrade() == -1
//           for Student exStudent("Geo", "Jon", 3);
//              with grades 100, 80, 75,
//              exStudent.avgGrade() == 85
//----- 
double Student::avgGrade() const
{
    double sumGrades = 0;

    if (numGrades == 0)
    {
        return -1;
    }
    else
    {
        for (int i=0; i < numGrades; i++)
        {
            sumGrades += gradesArray[i];
        }
        
        // KNOW numGrades != 0...
        return sumGrades / numGrades;
    }
}

//-----
// Contract: hasHigherAvgThan : Student -> bool
// Purpose: returns true if calling Student has
//          an average grade higher than 
//          otherStudent; returns false otherwise.
//
// Examples: if Student student1("A", "A", 3)
//              has grades 100, 80, 75,
//           Student student2("B", "B", 4)
//              has grades 80, 80, 90, 90, and
//           Student student3("C", "C", 3)
//              has grades 86, 87, 88,
//           then:
//   student1.hasHigherAvgThan(student2) == false
//   student3.hasHigherAvgThan(student2) == true
//   student1.hasHigherAvgThan(student3) == false
//-----
bool Student::hasHigherAvgThan(Student otherStudent) const
{
    return (avgGrade() > otherStudent.avgGrade());
}